• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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