1 // Copyright 2007-2008 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 <signal.h>
29
30 #include "sys/stat.h"
31 #include "v8.h"
32
33 #include "debug.h"
34 #include "ic-inl.h"
35 #include "runtime.h"
36 #include "serialize.h"
37 #include "scopeinfo.h"
38 #include "snapshot.h"
39 #include "cctest.h"
40
41 using namespace v8::internal;
42
43 static const unsigned kCounters = 256;
44 static int local_counters[kCounters];
45 static const char* local_counter_names[kCounters];
46
47
CounterHash(const char * s)48 static unsigned CounterHash(const char* s) {
49 unsigned hash = 0;
50 while (*++s) {
51 hash |= hash << 5;
52 hash += *s;
53 }
54 return hash;
55 }
56
57
58 // Callback receiver to track counters in test.
counter_function(const char * name)59 static int* counter_function(const char* name) {
60 unsigned hash = CounterHash(name) % kCounters;
61 unsigned original_hash = hash;
62 USE(original_hash);
63 while (true) {
64 if (local_counter_names[hash] == name) {
65 return &local_counters[hash];
66 }
67 if (local_counter_names[hash] == 0) {
68 local_counter_names[hash] = name;
69 return &local_counters[hash];
70 }
71 if (strcmp(local_counter_names[hash], name) == 0) {
72 return &local_counters[hash];
73 }
74 hash = (hash + 1) % kCounters;
75 ASSERT(hash != original_hash); // Hash table has been filled up.
76 }
77 }
78
79
80 template <class T>
AddressOf(T id)81 static Address AddressOf(T id) {
82 return ExternalReference(id).address();
83 }
84
85
86 template <class T>
Encode(const ExternalReferenceEncoder & encoder,T id)87 static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) {
88 return encoder.Encode(AddressOf(id));
89 }
90
91
make_code(TypeCode type,int id)92 static int make_code(TypeCode type, int id) {
93 return static_cast<uint32_t>(type) << kReferenceTypeShift | id;
94 }
95
96
register_code(int reg)97 static int register_code(int reg) {
98 return Debug::k_register_address << kDebugIdShift | reg;
99 }
100
101
TEST(ExternalReferenceEncoder)102 TEST(ExternalReferenceEncoder) {
103 StatsTable::SetCounterFunction(counter_function);
104 Heap::Setup(false);
105 ExternalReferenceEncoder encoder;
106 CHECK_EQ(make_code(BUILTIN, Builtins::ArrayCode),
107 Encode(encoder, Builtins::ArrayCode));
108 CHECK_EQ(make_code(RUNTIME_FUNCTION, Runtime::kAbort),
109 Encode(encoder, Runtime::kAbort));
110 CHECK_EQ(make_code(IC_UTILITY, IC::kLoadCallbackProperty),
111 Encode(encoder, IC_Utility(IC::kLoadCallbackProperty)));
112 CHECK_EQ(make_code(DEBUG_ADDRESS, register_code(3)),
113 Encode(encoder, Debug_Address(Debug::k_register_address, 3)));
114 ExternalReference keyed_load_function_prototype =
115 ExternalReference(&Counters::keyed_load_function_prototype);
116 CHECK_EQ(make_code(STATS_COUNTER, Counters::k_keyed_load_function_prototype),
117 encoder.Encode(keyed_load_function_prototype.address()));
118 ExternalReference passed_function =
119 ExternalReference::builtin_passed_function();
120 CHECK_EQ(make_code(UNCLASSIFIED, 1),
121 encoder.Encode(passed_function.address()));
122 ExternalReference the_hole_value_location =
123 ExternalReference::the_hole_value_location();
124 CHECK_EQ(make_code(UNCLASSIFIED, 2),
125 encoder.Encode(the_hole_value_location.address()));
126 ExternalReference stack_guard_limit_address =
127 ExternalReference::address_of_stack_guard_limit();
128 CHECK_EQ(make_code(UNCLASSIFIED, 4),
129 encoder.Encode(stack_guard_limit_address.address()));
130 CHECK_EQ(make_code(UNCLASSIFIED, 10),
131 encoder.Encode(ExternalReference::debug_break().address()));
132 CHECK_EQ(make_code(UNCLASSIFIED, 6),
133 encoder.Encode(ExternalReference::new_space_start().address()));
134 CHECK_EQ(make_code(UNCLASSIFIED, 3),
135 encoder.Encode(ExternalReference::roots_address().address()));
136 }
137
138
TEST(ExternalReferenceDecoder)139 TEST(ExternalReferenceDecoder) {
140 StatsTable::SetCounterFunction(counter_function);
141 Heap::Setup(false);
142 ExternalReferenceDecoder decoder;
143 CHECK_EQ(AddressOf(Builtins::ArrayCode),
144 decoder.Decode(make_code(BUILTIN, Builtins::ArrayCode)));
145 CHECK_EQ(AddressOf(Runtime::kAbort),
146 decoder.Decode(make_code(RUNTIME_FUNCTION, Runtime::kAbort)));
147 CHECK_EQ(AddressOf(IC_Utility(IC::kLoadCallbackProperty)),
148 decoder.Decode(make_code(IC_UTILITY, IC::kLoadCallbackProperty)));
149 CHECK_EQ(AddressOf(Debug_Address(Debug::k_register_address, 3)),
150 decoder.Decode(make_code(DEBUG_ADDRESS, register_code(3))));
151 ExternalReference keyed_load_function =
152 ExternalReference(&Counters::keyed_load_function_prototype);
153 CHECK_EQ(keyed_load_function.address(),
154 decoder.Decode(
155 make_code(STATS_COUNTER,
156 Counters::k_keyed_load_function_prototype)));
157 CHECK_EQ(ExternalReference::builtin_passed_function().address(),
158 decoder.Decode(make_code(UNCLASSIFIED, 1)));
159 CHECK_EQ(ExternalReference::the_hole_value_location().address(),
160 decoder.Decode(make_code(UNCLASSIFIED, 2)));
161 CHECK_EQ(ExternalReference::address_of_stack_guard_limit().address(),
162 decoder.Decode(make_code(UNCLASSIFIED, 4)));
163 CHECK_EQ(ExternalReference::debug_break().address(),
164 decoder.Decode(make_code(UNCLASSIFIED, 10)));
165 CHECK_EQ(ExternalReference::new_space_start().address(),
166 decoder.Decode(make_code(UNCLASSIFIED, 6)));
167 }
168
169
Serialize()170 static void Serialize() {
171 #ifdef DEBUG
172 FLAG_debug_serialization = true;
173 #endif
174 StatsTable::SetCounterFunction(counter_function);
175
176 v8::HandleScope scope;
177 const int kExtensionCount = 1;
178 const char* extension_list[kExtensionCount] = { "v8/gc" };
179 v8::ExtensionConfiguration extensions(kExtensionCount, extension_list);
180 Serializer::Enable();
181 v8::Persistent<v8::Context> env = v8::Context::New(&extensions);
182 env->Enter();
183
184 Snapshot::WriteToFile(FLAG_testing_serialization_file);
185 }
186
187
188 // Test that the whole heap can be serialized when running from the
189 // internal snapshot.
190 // (Smoke test.)
TEST(SerializeInternal)191 TEST(SerializeInternal) {
192 Snapshot::Initialize(NULL);
193 Serialize();
194 }
195
196
197 // Test that the whole heap can be serialized when running from a
198 // bootstrapped heap.
199 // (Smoke test.)
TEST(Serialize)200 TEST(Serialize) {
201 if (Snapshot::IsEnabled()) return;
202 Serialize();
203 }
204
205
206 // Test that the heap isn't destroyed after a serialization.
TEST(SerializeNondestructive)207 TEST(SerializeNondestructive) {
208 if (Snapshot::IsEnabled()) return;
209 StatsTable::SetCounterFunction(counter_function);
210 v8::HandleScope scope;
211 Serializer::Enable();
212 v8::Persistent<v8::Context> env = v8::Context::New();
213 v8::Context::Scope context_scope(env);
214 Serializer().Serialize();
215 const char* c_source = "\"abcd\".charAt(2) == 'c'";
216 v8::Local<v8::String> source = v8::String::New(c_source);
217 v8::Local<v8::Script> script = v8::Script::Compile(source);
218 v8::Local<v8::Value> value = script->Run();
219 CHECK(value->BooleanValue());
220 }
221
222 //----------------------------------------------------------------------------
223 // Tests that the heap can be deserialized.
224
Deserialize()225 static void Deserialize() {
226 #ifdef DEBUG
227 FLAG_debug_serialization = true;
228 #endif
229 CHECK(Snapshot::Initialize(FLAG_testing_serialization_file));
230 }
231
232
SanityCheck()233 static void SanityCheck() {
234 v8::HandleScope scope;
235 #ifdef DEBUG
236 Heap::Verify();
237 #endif
238 CHECK(Top::global()->IsJSObject());
239 CHECK(Top::global_context()->IsContext());
240 CHECK(Top::special_function_table()->IsFixedArray());
241 CHECK(Heap::symbol_table()->IsSymbolTable());
242 CHECK(!Factory::LookupAsciiSymbol("Empty")->IsFailure());
243 }
244
245
DEPENDENT_TEST(Deserialize,Serialize)246 DEPENDENT_TEST(Deserialize, Serialize) {
247 v8::HandleScope scope;
248
249 Deserialize();
250
251 SanityCheck();
252 }
253
DEPENDENT_TEST(DeserializeAndRunScript,Serialize)254 DEPENDENT_TEST(DeserializeAndRunScript, Serialize) {
255 v8::HandleScope scope;
256
257 Deserialize();
258
259 const char* c_source = "\"1234\".length";
260 v8::Local<v8::String> source = v8::String::New(c_source);
261 v8::Local<v8::Script> script = v8::Script::Compile(source);
262 CHECK_EQ(4, script->Run()->Int32Value());
263 }
264
265
DEPENDENT_TEST(DeserializeNatives,Serialize)266 DEPENDENT_TEST(DeserializeNatives, Serialize) {
267 v8::HandleScope scope;
268
269 Deserialize();
270
271 const char* c_source = "\"abcd\".charAt(2) == 'c'";
272 v8::Local<v8::String> source = v8::String::New(c_source);
273 v8::Local<v8::Script> script = v8::Script::Compile(source);
274 v8::Local<v8::Value> value = script->Run();
275 CHECK(value->BooleanValue());
276 }
277
278
DEPENDENT_TEST(DeserializeExtensions,Serialize)279 DEPENDENT_TEST(DeserializeExtensions, Serialize) {
280 v8::HandleScope scope;
281
282 Deserialize();
283 const char* c_source = "gc();";
284 v8::Local<v8::String> source = v8::String::New(c_source);
285 v8::Local<v8::Script> script = v8::Script::Compile(source);
286 v8::Local<v8::Value> value = script->Run();
287 CHECK(value->IsUndefined());
288 }
289