v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-alloc.cc
Go to the documentation of this file.
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 #include "accessors.h"
30 
31 #include "cctest.h"
32 
33 
34 using namespace v8::internal;
35 
36 
37 static inline void SimulateFullSpace(PagedSpace* space) {
38  int old_linear_size = static_cast<int>(space->limit() - space->top());
39  space->Free(space->top(), old_linear_size);
40  space->SetTop(space->limit(), space->limit());
41  space->ResetFreeList();
42  space->ClearStats();
43 }
44 
45 
46 static MaybeObject* AllocateAfterFailures() {
47  static int attempts = 0;
48  if (++attempts < 3) return Failure::RetryAfterGC();
49  Heap* heap = Isolate::Current()->heap();
50 
51  // New space.
52  NewSpace* new_space = heap->new_space();
53  static const int kNewSpaceFillerSize = ByteArray::SizeFor(0);
54  while (new_space->Available() > kNewSpaceFillerSize) {
55  int available_before = static_cast<int>(new_space->Available());
56  CHECK(!heap->AllocateByteArray(0)->IsFailure());
57  if (available_before == new_space->Available()) {
58  // It seems that we are avoiding new space allocations when
59  // allocation is forced, so no need to fill up new space
60  // in order to make the test harder.
61  break;
62  }
63  }
64  CHECK(!heap->AllocateByteArray(100)->IsFailure());
65  CHECK(!heap->AllocateFixedArray(100, NOT_TENURED)->IsFailure());
66 
67  // Make sure we can allocate through optimized allocation functions
68  // for specific kinds.
69  CHECK(!heap->AllocateFixedArray(100)->IsFailure());
70  CHECK(!heap->AllocateHeapNumber(0.42)->IsFailure());
71  CHECK(!heap->AllocateArgumentsObject(Smi::FromInt(87), 10)->IsFailure());
72  Object* object = heap->AllocateJSObject(
73  *Isolate::Current()->object_function())->ToObjectChecked();
74  CHECK(!heap->CopyJSObject(JSObject::cast(object))->IsFailure());
75 
76  // Old data space.
77  SimulateFullSpace(heap->old_data_space());
78  CHECK(!heap->AllocateRawAsciiString(100, TENURED)->IsFailure());
79 
80  // Old pointer space.
81  SimulateFullSpace(heap->old_pointer_space());
82  CHECK(!heap->AllocateFixedArray(10000, TENURED)->IsFailure());
83 
84  // Large object space.
85  static const int kLargeObjectSpaceFillerLength = 300000;
86  static const int kLargeObjectSpaceFillerSize = FixedArray::SizeFor(
87  kLargeObjectSpaceFillerLength);
88  ASSERT(kLargeObjectSpaceFillerSize > heap->old_pointer_space()->AreaSize());
89  while (heap->OldGenerationSpaceAvailable() > kLargeObjectSpaceFillerSize) {
90  CHECK(!heap->AllocateFixedArray(kLargeObjectSpaceFillerLength, TENURED)->
91  IsFailure());
92  }
93  CHECK(!heap->AllocateFixedArray(kLargeObjectSpaceFillerLength, TENURED)->
94  IsFailure());
95 
96  // Map space.
97  SimulateFullSpace(heap->map_space());
98  int instance_size = JSObject::kHeaderSize;
99  CHECK(!heap->AllocateMap(JS_OBJECT_TYPE, instance_size)->IsFailure());
100 
101  // Test that we can allocate in old pointer space and code space.
102  CHECK(!heap->AllocateFixedArray(100, TENURED)->IsFailure());
103  CHECK(!heap->CopyCode(Isolate::Current()->builtins()->builtin(
104  Builtins::kIllegal))->IsFailure());
105 
106  // Return success.
107  return Smi::FromInt(42);
108 }
109 
110 
111 static Handle<Object> Test() {
112  CALL_HEAP_FUNCTION(ISOLATE, AllocateAfterFailures(), Object);
113 }
114 
115 
116 TEST(StressHandles) {
118  v8::HandleScope scope;
119  env->Enter();
120  Handle<Object> o = Test();
121  CHECK(o->IsSmi() && Smi::cast(*o)->value() == 42);
122  env->Exit();
123 }
124 
125 
126 static MaybeObject* TestAccessorGet(Object* object, void*) {
127  return AllocateAfterFailures();
128 }
129 
130 
132  TestAccessorGet,
133  0,
134  0
135 };
136 
137 
138 TEST(StressJS) {
140  v8::HandleScope scope;
141  env->Enter();
142  Handle<JSFunction> function =
143  FACTORY->NewFunction(FACTORY->function_symbol(), FACTORY->null_value());
144  // Force the creation of an initial map and set the code to
145  // something empty.
146  FACTORY->NewJSObject(function);
147  function->ReplaceCode(Isolate::Current()->builtins()->builtin(
148  Builtins::kEmptyFunction));
149  // Patch the map to have an accessor for "get".
150  Handle<Map> map(function->initial_map());
151  Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
152  Handle<Foreign> foreign = FACTORY->NewForeign(&kDescriptor);
153  instance_descriptors = FACTORY->CopyAppendForeignDescriptor(
154  instance_descriptors,
155  FACTORY->NewStringFromAscii(Vector<const char>("get", 3)),
156  foreign,
157  static_cast<PropertyAttributes>(0));
158  map->set_instance_descriptors(*instance_descriptors);
159  // Add the Foo constructor the global object.
160  env->Global()->Set(v8::String::New("Foo"), v8::Utils::ToLocal(function));
161  // Call the accessor through JavaScript.
162  v8::Handle<v8::Value> result =
163  v8::Script::Compile(v8::String::New("(new Foo).get"))->Run();
164  CHECK_EQ(42, result->Int32Value());
165  env->Exit();
166 }
167 
168 
169 // CodeRange test.
170 // Tests memory management in a CodeRange by allocating and freeing blocks,
171 // using a pseudorandom generator to choose block sizes geometrically
172 // distributed between 2 * Page::kPageSize and 2^5 + 1 * Page::kPageSize.
173 // Ensure that the freed chunks are collected and reused by allocating (in
174 // total) more than the size of the CodeRange.
175 
176 // This pseudorandom generator does not need to be particularly good.
177 // Use the lower half of the V8::Random() generator.
178 unsigned int Pseudorandom() {
179  static uint32_t lo = 2345;
180  lo = 18273 * (lo & 0xFFFF) + (lo >> 16); // Provably not 0.
181  return lo & 0xFFFF;
182 }
183 
184 
185 // Plain old data class. Represents a block of allocated memory.
186 class Block {
187  public:
188  Block(Address base_arg, int size_arg)
189  : base(base_arg), size(size_arg) {}
190 
192  int size;
193 };
194 
195 
197  const int code_range_size = 32*MB;
198  OS::SetUp();
199  Isolate::Current()->InitializeLoggingAndCounters();
200  CodeRange* code_range = new CodeRange(Isolate::Current());
201  code_range->SetUp(code_range_size);
202  int current_allocated = 0;
203  int total_allocated = 0;
204  List<Block> blocks(1000);
205 
206  while (total_allocated < 5 * code_range_size) {
207  if (current_allocated < code_range_size / 10) {
208  // Allocate a block.
209  // Geometrically distributed sizes, greater than
210  // Page::kMaxNonCodeHeapObjectSize (which is greater than code page area).
211  // TODO(gc): instead of using 3 use some contant based on code_range_size
212  // kMaxHeapObjectSize.
213  size_t requested =
215  Pseudorandom() % 5000 + 1;
216  size_t allocated = 0;
217  Address base = code_range->AllocateRawMemory(requested, &allocated);
218  CHECK(base != NULL);
219  blocks.Add(Block(base, static_cast<int>(allocated)));
220  current_allocated += static_cast<int>(allocated);
221  total_allocated += static_cast<int>(allocated);
222  } else {
223  // Free a block.
224  int index = Pseudorandom() % blocks.length();
225  code_range->FreeRawMemory(blocks[index].base, blocks[index].size);
226  current_allocated -= blocks[index].size;
227  if (index < blocks.length() - 1) {
228  blocks[index] = blocks.RemoveLast();
229  } else {
230  blocks.RemoveLast();
231  }
232  }
233  }
234 
235  code_range->TearDown();
236  delete code_range;
237 }
byte * Address
Definition: globals.h:172
MUST_USE_RESULT MaybeObject * CopyCode(Code *code)
Definition: heap.cc:3546
static Local< Script > Compile(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1560
#define CHECK_EQ(expected, value)
Definition: checks.h:219
MUST_USE_RESULT MaybeObject * AllocateFixedArray(int length, PretenureFlag pretenure)
Definition: heap.cc:4712
void SetTop(Address top, Address limit)
Definition: spaces.h:1530
bool SetUp(const size_t requested_size)
Definition: spaces.cc:135
static Smi * FromInt(int value)
Definition: objects-inl.h:973
MUST_USE_RESULT MaybeObject * AllocateJSObject(JSFunction *constructor, PretenureFlag pretenure=NOT_TENURED)
Definition: heap.cc:3931
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4655
MUST_USE_RESULT MaybeObject * AllocateByteArray(int length, PretenureFlag pretenure)
Definition: heap.cc:3406
Address base
Definition: test-alloc.cc:191
MUST_USE_RESULT MaybeObject * AllocateRawAsciiString(int length, PretenureFlag pretenure=NOT_TENURED)
Definition: heap.cc:4472
#define ASSERT(condition)
Definition: checks.h:270
#define CHECK(condition)
Definition: checks.h:56
MUST_USE_RESULT MaybeObject * CopyJSObject(JSObject *source)
Definition: heap.cc:4144
PropertyAttributes
MUST_USE_RESULT MaybeObject * AllocateHeapNumber(double value, PretenureFlag pretenure)
Definition: heap.cc:2407
static Smi * cast(Object *object)
unsigned int Pseudorandom()
Definition: test-alloc.cc:178
static Failure * RetryAfterGC()
Definition: objects-inl.h:1032
#define CALL_HEAP_FUNCTION(ISOLATE, FUNCTION_CALL, TYPE)
Definition: heap-inl.h:549
V8EXPORT int32_t Int32Value() const
Definition: api.cc:2654
intptr_t Available()
Definition: spaces.h:2137
OldSpace * old_pointer_space()
Definition: heap.h:500
static const int kMaxNonCodeHeapObjectSize
Definition: spaces.h:701
MUST_USE_RESULT Address AllocateRawMemory(const size_t requested, size_t *allocated)
Definition: spaces.cc:211
int Free(Address start, int size_in_bytes)
Definition: spaces.h:1519
static Local< Context > ToLocal(v8::internal::Handle< v8::internal::Context > obj)
static int SizeFor(int length)
Definition: objects.h:2288
#define ISOLATE
Definition: isolate.h:1410
int size
Definition: test-alloc.cc:192
static int SizeFor(int length)
Definition: objects.h:3610
MUST_USE_RESULT MaybeObject * AllocateArgumentsObject(Object *callee, int length)
Definition: heap.cc:3709
Block(Address base_arg, int size_arg)
Definition: test-alloc.cc:188
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
Definition: flags.cc:274
static void SetUp()
static const int kHeaderSize
Definition: objects.h:2115
MapSpace * map_space()
Definition: heap.h:503
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:38
#define FACTORY
Definition: isolate.h:1409
const AccessorDescriptor kDescriptor
Definition: test-alloc.cc:131
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4308
void FreeRawMemory(Address buf, size_t length)
Definition: spaces.cc:245
intptr_t OldGenerationSpaceAvailable()
Definition: heap.h:1354
NewSpace * new_space()
Definition: heap.h:499
MUST_USE_RESULT MaybeObject * AllocateMap(InstanceType instance_type, int instance_size, ElementsKind elements_kind=TERMINAL_FAST_ELEMENTS_KIND)
Definition: heap.cc:2011
static JSObject * cast(Object *obj)
OldSpace * old_data_space()
Definition: heap.h:501
const int MB
Definition: globals.h:222