Fixed type checking for multidimensional arrays.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
7 * JITCraft is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * JITCraft. If not, see http://www.gnu.org/licenses/.
21 #include "../Utility.h"
24 #include "../Strings.h"
26 #include "BytecodeEmitter.h"
29 #include "../Spaces-inl.h"
30 #include "../Heap-inl.h"
34 StringTable::StringTable()
35 : set_(ZoneAllocatorPolicy()),
41 StringTable::initialize()
43 assert(!initialized_);
51 StringTable::add(Handle<String> name, unsigned *indexp)
53 if (!initialized_ && !initialize())
56 Set::Insert p = set_.findForAdd(*name);
62 if (strings_.length() > INT_MAX) {
63 ZONE()->reportAllocationOverflow();
67 Entry e(name, strings_.length());
68 if (!strings_.append(e))
80 StringTable::accept(VirtualObjectVisitor *visitor)
82 for (size_t i = 0; i < strings_.length(); i++)
83 visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
86 BytecodeEmitter::BytecodeEmitter()
88 buffer_(inline_buffer_),
90 buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
96 lastCodePosition_ = 0;
100 BytecodeEmitter::~BytecodeEmitter()
102 for (size_t i = 0; i < oopRecords_.length(); i++)
103 delete oopRecords_[i];
107 BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
109 for (size_t i = 0; i < objects_.length(); i++)
110 visitor->visit(&objects_[i]);
112 strings_.accept(visitor);
116 BytecodeEmitter::growBuffer(size_t nbytes)
119 buffer_pos_ = buffer_;
123 size_t newSize = size_t((buffer_end_ - buffer_) * 2);
124 if (newSize >= MAX_LENGTH) {
126 buffer_pos_ = buffer_;
127 ZONE()->reportOutOfMemory();
132 if (buffer_ == inline_buffer_)
133 newBuffer = (bytecode *)malloc(newSize);
135 newBuffer = (bytecode *)realloc(buffer_, newSize);
137 // If we can't allocate a buffer, reset the buffer to the start and set
138 // a flag to indicate out-of-memory.
141 buffer_pos_ = buffer_;
142 ZONE()->reportOutOfMemory();
146 if (buffer_ == inline_buffer_)
147 memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
149 buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
151 buffer_end_ = buffer_ + newSize;
152 assert(buffer_pos_ + nbytes < buffer_end_);
158 BytecodeEmitter::recordOops()
160 OopRecord *record = new OopRecord(oopMap_.length(), position());
162 if (!record->slots.ensure(record->depth)) {
167 bool hadOops = false;
168 for (size_t i = 0; i < oopMap_.length(); i++) {
169 bool bit = oopMap_[i];
170 record->slots.infallibleAppend(bit);
179 oom_ &= oopRecords_.append(record);
183 BytecodeEmitter::note_position(const SourcePosition &pos)
185 assert(pos.line > 0);
186 assert(unsigned(pos.line) >= firstLine_);
188 unsigned lineDelta = unsigned(pos.line) - firstLine_;
189 unsigned pcDelta = unsigned(position()) - lastCodePosition_;
191 sourcemap_.writeUint32(pcDelta);
192 sourcemap_.writeUint32(lineDelta);
193 sourcemap_.writeUint32(pos.col);
195 lastCodePosition_ = unsigned(position());
199 BytecodeEmitter::getglobal(Symbol *sym)
201 ensure(OP_GETGLOBAL_LENGTH);
202 writeOp(OP_GETGLOBAL);
203 writeUint32(addString(sym->name()));
204 if (sym->type()->isTraceable())
208 BytecodeEmitter::setglobal(Symbol *sym)
210 ensure(OP_SETGLOBAL_LENGTH);
211 writeOp(OP_SETGLOBAL);
212 writeUint32(addString(sym->name()));
213 if (sym->type()->isTraceable())
218 BytecodeEmitter::getlocal(VariableSymbol *var)
220 assert(var->storage() == VariableSymbol::Local);
221 ensure(OP_GETLOCAL_LENGTH);
222 writeOp(OP_GETLOCAL);
223 writeUint32(var->slot());
224 if (var->type()->isTraceable())
229 BytecodeEmitter::setlocal(VariableSymbol *var)
231 assert(var->storage() == VariableSymbol::Local);
232 ensure(OP_SETLOCAL_LENGTH);
233 writeOp(OP_SETLOCAL);
234 writeUint32(var->slot());
235 if (var->type()->isTraceable())
240 BytecodeEmitter::getarg(VariableSymbol *var)
242 assert(var->storage() == VariableSymbol::Arg);
243 ensure(OP_GETARG_LENGTH);
245 writeUint32(var->slot());
246 if (var->type()->isTraceable())
251 BytecodeEmitter::setarg(VariableSymbol *var)
253 assert(var->storage() == VariableSymbol::Arg);
254 ensure(OP_SETARG_LENGTH);
256 writeUint32(var->slot());
257 if (var->type()->isTraceable())
262 BytecodeEmitter::allocate(VariableSymbol *sym)
264 assert(sym->isVariable());
265 assert(sym->scope()->kind() == Scope::BLOCK);
267 switch (sym->scope()->kind()) {
270 // See overall comment on overflows.
271 assert(locals_.length() < UINT_MAX);
272 sym->allocate(VariableSymbol::Local, locals_.length());
273 if (!locals_.append(sym))
287 BytecodeEmitter::newref(VariableSymbol *var)
290 if (var->storage() == VariableSymbol::Local) {
291 ensure(OP_VARREF_LIFO_LENGTH);
292 writeOp(OP_VARREF_LIFO);
294 assert(var->storage() == VariableSymbol::Arg);
295 ensure(OP_ARGREF_LIFO_LENGTH);
296 writeOp(OP_ARGREF_LIFO);
298 writeUint32(var->slot());
303 BytecodeEmitter::finish()
308 if (oom() || zone->hasPendingException())
311 Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
314 memcpy(bytes->raw(), buffer(), length());
316 Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
320 for (size_t i = 0; i < objects_.length(); i++)
321 objects->set(zone, i, objects_[i]);
323 // If any stack slots hold gc pointers at potential failure points in the
324 // bytecode, record them now. We do this by building a list of tuples;
325 // each tuple contains the pc offset, and a bitset containing which stack
326 // slots must be scanned by the gc.
327 Local<ByteArray> safepoints(zone);
328 if (oopRecords_.length()) {
329 size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
330 size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
331 safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
335 Address cursor = safepoints->raw();
336 for (size_t i = 0; i < oopRecords_.length(); i++) {
337 OopRecord *record = oopRecords_[i];
338 assert(record->depth <= maxStackDepth());
340 *reinterpret_cast<unsigned *>(cursor) = record->offset;
342 unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
343 for (unsigned i = 0; i < record->depth; i++)
344 bits[i / 8] |= (1 << (i % 8));
346 cursor += bytesPerSafepoint;
349 assert(cursor == safepoints->raw() + gcmapSize);
352 Local<ByteArray> sourcemap(zone);
353 if (sourcemap_.length()) {
354 sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
358 memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
361 Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
364 for (size_t i = 0; i < strings_.stringCount(); i++)
365 strings->set(zone, i, strings_.stringAt(i));
367 Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
370 for (size_t i = 0; i < locals_.length(); i++)
371 locals->set(zone, i, locals_[i]->type());
373 Local<Code> code(zone);
375 code = Code::New(zone,