Normalise line endings.
Normalise line endings.
1.1 --- a/jitcraft.sln Mon Jun 10 00:46:29 2013 +0100
1.2 +++ b/jitcraft.sln Mon Jun 10 01:04:43 2013 +0100
1.3 @@ -1,23 +1,23 @@
1.4 -
1.5 -Microsoft Visual Studio Solution File, Format Version 11.00
1.6 -# Visual C++ Express 2010
1.7 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jitcraft", "src\jitcraft.vcxproj", "{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}"
1.8 -EndProject
1.9 -Global
1.10 - GlobalSection(SolutionConfigurationPlatforms) = preSolution
1.11 - Debug - Library|Win32 = Debug - Library|Win32
1.12 - Debug|Win32 = Debug|Win32
1.13 - Release|Win32 = Release|Win32
1.14 - EndGlobalSection
1.15 - GlobalSection(ProjectConfigurationPlatforms) = postSolution
1.16 - {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.ActiveCfg = Debug - Library|Win32
1.17 - {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.Build.0 = Debug - Library|Win32
1.18 - {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.ActiveCfg = Debug|Win32
1.19 - {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.Build.0 = Debug|Win32
1.20 - {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.ActiveCfg = Release|Win32
1.21 - {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.Build.0 = Release|Win32
1.22 - EndGlobalSection
1.23 - GlobalSection(SolutionProperties) = preSolution
1.24 - HideSolutionNode = FALSE
1.25 - EndGlobalSection
1.26 -EndGlobal
1.27 +
1.28 +Microsoft Visual Studio Solution File, Format Version 11.00
1.29 +# Visual C++ Express 2010
1.30 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jitcraft", "src\jitcraft.vcxproj", "{E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}"
1.31 +EndProject
1.32 +Global
1.33 + GlobalSection(SolutionConfigurationPlatforms) = preSolution
1.34 + Debug - Library|Win32 = Debug - Library|Win32
1.35 + Debug|Win32 = Debug|Win32
1.36 + Release|Win32 = Release|Win32
1.37 + EndGlobalSection
1.38 + GlobalSection(ProjectConfigurationPlatforms) = postSolution
1.39 + {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.ActiveCfg = Debug - Library|Win32
1.40 + {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug - Library|Win32.Build.0 = Debug - Library|Win32
1.41 + {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.ActiveCfg = Debug|Win32
1.42 + {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Debug|Win32.Build.0 = Debug|Win32
1.43 + {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.ActiveCfg = Release|Win32
1.44 + {E12034DC-E8CB-4B49-AC0A-0D27CDED9A50}.Release|Win32.Build.0 = Release|Win32
1.45 + EndGlobalSection
1.46 + GlobalSection(SolutionProperties) = preSolution
1.47 + HideSolutionNode = FALSE
1.48 + EndGlobalSection
1.49 +EndGlobal
2.1 --- a/product.version Mon Jun 10 00:46:29 2013 +0100
2.2 +++ b/product.version Mon Jun 10 01:04:43 2013 +0100
2.3 @@ -1,1 +1,1 @@
2.4 -0.0.2-alpha
2.5 +0.0.2-alpha
3.1 --- a/src/Array.cpp Mon Jun 10 00:46:29 2013 +0100
3.2 +++ b/src/Array.cpp Mon Jun 10 01:04:43 2013 +0100
3.3 @@ -1,378 +1,378 @@
3.4 -/* vim: set ts=4 sw=4 tw=99 et:
3.5 - *
3.6 - * Copyright (C) 2012 David Anderson
3.7 - *
3.8 - * This file is part of SourcePawn.
3.9 - *
3.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
3.11 - * the terms of the GNU General Public License as published by the Free
3.12 - * Software Foundation, either version 3 of the License, or (at your option)
3.13 - * any later version.
3.14 - *
3.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
3.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
3.18 - *
3.19 - * You should have received a copy of the GNU General Public License along with
3.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
3.21 - */
3.22 -#include <string.h>
3.23 -#include "Array.h"
3.24 -#include "FixedArray.h"
3.25 -#include "Heap.h"
3.26 -#include "Zone.h"
3.27 -#include "Structures.h"
3.28 -#include "Heap-inl.h"
3.29 -
3.30 -using namespace ke;
3.31 -
3.32 -ArrayMap *
3.33 -ArrayMap::New(Zone *zone, Handle<ArrayType> type)
3.34 -{
3.35 - Local<Map> obj(zone, zone->allocateMap(MapKind_Array, sizeof(ArrayMap), MapKind_MetaArray));
3.36 - if (!obj)
3.37 - return NULL;
3.38 -
3.39 - Local<ArrayMap> map(zone, ArrayMap::cast(obj));
3.40 - map->type_ = type;
3.41 - return map;
3.42 -}
3.43 -
3.44 -ArrayMap *
3.45 -ArrayMap::NewDependent(Zone *zone, Handle<ArrayType> type)
3.46 -{
3.47 - Local<Map> obj(zone, zone->allocateMap(MapKind_DependentArray, sizeof(ArrayMap), MapKind_MetaArray));
3.48 - if (!obj)
3.49 - return NULL;
3.50 -
3.51 - Local<ArrayMap> map(zone, ArrayMap::cast(obj));
3.52 - map->type_ = type;
3.53 - return map;
3.54 -}
3.55 -
3.56 -Array *
3.57 -Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
3.58 -{
3.59 - assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength());
3.60 -
3.61 - if (nelements > (INT_MAX / SizeForElement(map->type()))) {
3.62 - zone->reportError(Message_ArraySizeTooBig);
3.63 - return NULL;
3.64 - }
3.65 -
3.66 - size_t bytes = sizeof(Array);
3.67 - if (map->type()->hasInlineElements())
3.68 - bytes += SizeForElement(map->type()) * nelements;
3.69 -
3.70 - Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
3.71 - if (!array)
3.72 - return NULL;
3.73 -
3.74 - array->length_ = 0;
3.75 - array->elements_ = NULL;
3.76 -
3.77 - if (map->type()->hasInlineElements()) {
3.78 - // This must be a fixed array containing no traceables.
3.79 - assert(nelements > 0);
3.80 - assert(map->type()->isFixedLength());
3.81 - assert(!map->type()->contained()->isTraceable());
3.82 -
3.83 - // Compute an interior |elements_| pointer, such that if elements_
3.84 - // is accessed like a FixedArray, we reach the appropriate vector.
3.85 - array->elements_ = Address((Array *)array + 1) - ByteArray::offsetToElements();
3.86 - array->length_ = nelements;
3.87 - memset(array->bytes(), 0, SizeForElement(map->type()) * nelements);
3.88 - return array;
3.89 - }
3.90 -
3.91 - // If there is nothing to allocate, we don't bother creating elements yet.
3.92 - if (!nelements)
3.93 - return array;
3.94 -
3.95 - if (!map->type()->contained()->isTraceable()) {
3.96 - size_t nbytes = SizeForElement(map->type()) * nelements;
3.97 - Local<ByteArray> elements(zone, ByteArray::New(zone, nbytes, tenure));
3.98 - if (!elements)
3.99 - return NULL;
3.100 -
3.101 - array->updateLengthAndElements(zone, nelements, elements);
3.102 - return array;
3.103 - }
3.104 -
3.105 - Local<FixedArray> elements(zone, FixedArray::New(zone, nelements, tenure));
3.106 - if (!elements)
3.107 - return NULL;
3.108 -
3.109 - array->updateLengthAndElements(zone, nelements, elements);
3.110 -
3.111 - // If this is an array of structs, we're required to allocate those structs now.
3.112 - if (map->type()->contained()->isStruct()) {
3.113 - Local<StructType> childType(zone, StructType::cast(map->type()->contained()));
3.114 - Local<StructMap> childMap(zone, childType->newMap());
3.115 - Local<Struct> child(zone);
3.116 - for (unsigned i = 0; i < nelements; i++) {
3.117 - child = Struct::New(zone, childMap, tenure);
3.118 - if (!child)
3.119 - return NULL;
3.120 -
3.121 - elements->set(zone, i, child);
3.122 - }
3.123 - }
3.124 -
3.125 - return array;
3.126 -}
3.127 -
3.128 -static Array *
3.129 -ConstructSizedArray(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH],
3.130 - unsigned level, Heap::Tenure tenure)
3.131 -{
3.132 - Local<Array> array(zone, Array::NewRaw(zone, map, dims[level], tenure));
3.133 - if (!array)
3.134 - return NULL;
3.135 -
3.136 - if (map->type()->contained()->isArray()) {
3.137 - Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
3.138 - Local<ArrayMap> childMap(zone, childType->newMap());
3.139 - Local<Array> child(zone);
3.140 -
3.141 - for (unsigned i = 0; i < unsigned(dims[level]); i++) {
3.142 - child = ConstructSizedArray(zone, childMap, dims, level + 1, tenure);
3.143 - if (!child)
3.144 - return NULL;
3.145 -
3.146 - array->writeObject(zone, i, child);
3.147 - }
3.148 - }
3.149 -
3.150 - return array;
3.151 -}
3.152 -
3.153 -Array *
3.154 -Array::NewSized(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH], Heap::Tenure tenure)
3.155 -{
3.156 - for (size_t i = 0; i < map->type()->levels(); i++) {
3.157 - if (dims[i] < 0) {
3.158 - zone->reportError(Message_InvalidDimensionSize, dims[i], i);
3.159 - return NULL;
3.160 - }
3.161 - }
3.162 -
3.163 - return ConstructSizedArray(zone, map, dims, 0, tenure);
3.164 -}
3.165 -
3.166 -static Array *
3.167 -ConstructFixedArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
3.168 -{
3.169 - unsigned length = map->type()->fixedLength();
3.170 - Local<Array> array(zone, Array::NewRaw(zone, map, length, tenure));
3.171 - if (!array)
3.172 - return NULL;
3.173 -
3.174 - if (map->type()->contained()->isArray()) {
3.175 - Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
3.176 - Local<ArrayMap> childMap(zone, childType->newMap());
3.177 - Local<Array> child(zone);
3.178 -
3.179 - if (childMap->type()->isFixedLength()) {
3.180 - for (unsigned i = 0; i < length; i++) {
3.181 - child = ConstructFixedArray(zone, childMap, tenure);
3.182 - if (!child)
3.183 - return NULL;
3.184 -
3.185 - array->writeObject(zone, i, child);
3.186 - }
3.187 - } else {
3.188 - for (unsigned i = 0; i < length; i++) {
3.189 - child = Array::NewRaw(zone, childMap, 0, tenure);
3.190 - if (!child)
3.191 - return NULL;
3.192 -
3.193 - array->writeObject(zone, i, child);
3.194 - }
3.195 - }
3.196 - }
3.197 -
3.198 - return array;
3.199 -}
3.200 -
3.201 -Array *
3.202 -Array::NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
3.203 -{
3.204 - return ConstructFixedArray(zone, map, tenure);
3.205 -}
3.206 -
3.207 -Array *
3.208 -Array::NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure tenure)
3.209 -{
3.210 - assert(map->type()->isCharArray());
3.211 -
3.212 - Local<Array> array(zone);
3.213 -
3.214 - if (map->type()->isFixedLength())
3.215 - array = Array::NewFixed(zone, map, tenure);
3.216 - else
3.217 - array = Array::New1D(zone, map, length + 1, tenure);
3.218 - if (!array)
3.219 - return NULL;
3.220 -
3.221 - assert(array->length() >= length + 1);
3.222 - memcpy(array->chars(), buffer, length + 1);
3.223 - return array;
3.224 -}
3.225 -
3.226 -Array *
3.227 -Array::New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
3.228 -{
3.229 - assert(map->type()->levels());
3.230 - return Array::NewRaw(zone, map, elements, tenure);
3.231 -}
3.232 -
3.233 -Array *
3.234 -Array::NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
3.235 -{
3.236 - assert(!map->type()->isFixedLength());
3.237 -
3.238 - return Array::NewRaw(zone, map, 0, tenure);
3.239 -}
3.240 -
3.241 -Array *
3.242 -Array::NewExternal(Zone *zone, Handle<ArrayMap> map, void *buffer, unsigned length,
3.243 - Heap::Tenure tenure)
3.244 -{
3.245 - Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
3.246 - if (!array)
3.247 - return NULL;
3.248 -
3.249 - array->length_ = length;
3.250 - array->elements_ = Address(buffer) - ByteArray::offsetToElements();
3.251 - return array;
3.252 -}
3.253 -
3.254 -static bool
3.255 -CopyArrayElements(Zone *zone, Handle<Type> contained, Handle<Array> dest, Handle<Array> source)
3.256 -{
3.257 - if (contained->isTraceable()) {
3.258 - if (contained->isStruct()) {
3.259 - assert(dest->type()->contained() == contained);
3.260 - assert(source->length() == dest->length());
3.261 -
3.262 - Local<Struct> left(zone);
3.263 - Local<Struct> right(zone);
3.264 - for (unsigned i = 0; i < source->length(); i++) {
3.265 - left = Struct::cast(dest->readObject(i));
3.266 - right = Struct::cast(source->readObject(i));
3.267 - if (!Struct::Copy(zone, left, right))
3.268 - return false;
3.269 - }
3.270 - } else if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
3.271 - assert(ArrayType::cast(source->type())->fixedLength() ==
3.272 - ArrayType::cast(contained)->fixedLength());
3.273 -
3.274 - Local<Array> left(zone);
3.275 - Local<Array> right(zone);
3.276 - for (unsigned i = 0; i < source->length(); i++) {
3.277 - left = Array::cast(dest->readObject(i));
3.278 - right = Array::cast(source->readObject(i));
3.279 - if (!Array::ShallowCopy(zone, left, right))
3.280 - return false;
3.281 - }
3.282 - } else {
3.283 - assert(dest->length() == source->length());
3.284 - for (unsigned i = 0; i < source->length(); i++)
3.285 - dest->writeObject(zone, i, source->readObject(i));
3.286 - }
3.287 - } else {
3.288 - assert(contained->pod() == dest->type()->contained()->pod());
3.289 - assert(contained->pod() == PrimitiveType_Char
3.290 - ? source->length() <= dest->length()
3.291 - : source->length() == dest->length());
3.292 -
3.293 - assert(dest->length());
3.294 - memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
3.295 - }
3.296 - return true;
3.297 -}
3.298 -
3.299 -// Shallow copy an array. Fixed slots in the destination are copied from
3.300 -// the source, but otherwise, references are assigned.
3.301 -bool
3.302 -Array::ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source)
3.303 -{
3.304 - Local<Type> contained(zone, dest->type()->contained());
3.305 -
3.306 - return CopyArrayElements(zone, contained, dest, source);
3.307 -}
3.308 -
3.309 -Array *
3.310 -Array::DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure)
3.311 -{
3.312 - Local<ArrayMap> map(zone, ArrayMap::cast(source->map()));
3.313 -
3.314 - Local<Array> dest(zone, Array::NewRaw(zone, map, source->length(), tenure));
3.315 - if (!dest)
3.316 - return NULL;
3.317 -
3.318 - Local<Type> contained(zone, source->type()->contained());
3.319 - if (contained->isArray()) {
3.320 - assert(false);
3.321 - Local<Array> sub(zone);
3.322 - for (size_t i = 0; i < source->length(); i++) {
3.323 - sub = Array::cast(source->readObject(i));
3.324 - sub = DeepCopy(zone, sub, tenure);
3.325 - if (!sub)
3.326 - return NULL;
3.327 - dest->writeObject(zone, i, sub);
3.328 - }
3.329 - } else {
3.330 - if (!CopyArrayElements(zone, contained, dest, source))
3.331 - return NULL;
3.332 - }
3.333 -
3.334 - return dest;
3.335 -}
3.336 -
3.337 -Array *
3.338 -DependentArray::New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index)
3.339 -{
3.340 - Local<ArrayType> sourcetype(zone, source->type());
3.341 -
3.342 - // Right now we only support char arrays, to avoid nasty deep cloning
3.343 - // and to maybe cut off this feature as far as we can.
3.344 - assert(sourcetype->isCharArray());
3.345 - assert(map->type()->isCharArray());
3.346 -
3.347 - // We allow taking 0-length dependent strings. It's safe because any reads
3.348 - // or writes will fail.
3.349 - assert(index <= source->length());
3.350 -
3.351 - unsigned newlen = source->length() - index;
3.352 - unsigned eltsize = SizeForElement(sourcetype);
3.353 -
3.354 - if (!sourcetype->isFixedLength()) {
3.355 - // Simple case, just copy the array.
3.356 - Local<ArrayMap> map(zone, sourcetype->newMap());
3.357 -
3.358 - Local<Array> dest(zone, Array::NewRaw(zone, map, newlen, Heap::Tenure_Default));
3.359 - if (!dest)
3.360 - return NULL;
3.361 -
3.362 - memcpy(dest->bytes(),
3.363 - (Address)source->bytes() + (index * eltsize),
3.364 - newlen * eltsize);
3.365 - return dest;
3.366 - }
3.367 -
3.368 - Local<DependentArray> array(zone, DependentArray::cast(zone->allocate(map, sizeof(DependentArray), Heap::Tenure_Default)));
3.369 - if (!array)
3.370 - return NULL;
3.371 -
3.372 - // :GC: This is currently not safe for moving GC! Although we will mark
3.373 - // the object owning the interior pointer, the interior pointer could be
3.374 - // moved later. We will eventually need some way of dealing with this.
3.375 - Address elements = Address(source->bytes()) + (index * eltsize);
3.376 -
3.377 - array->root_ = source;
3.378 - array->length_ = newlen;
3.379 - array->elements_ = elements - ByteArray::offsetToElements();
3.380 - return array;
3.381 -}
3.382 +/* vim: set ts=4 sw=4 tw=99 et:
3.383 + *
3.384 + * Copyright (C) 2012 David Anderson
3.385 + *
3.386 + * This file is part of SourcePawn.
3.387 + *
3.388 + * SourcePawn is free software: you can redistribute it and/or modify it under
3.389 + * the terms of the GNU General Public License as published by the Free
3.390 + * Software Foundation, either version 3 of the License, or (at your option)
3.391 + * any later version.
3.392 + *
3.393 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
3.394 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.395 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
3.396 + *
3.397 + * You should have received a copy of the GNU General Public License along with
3.398 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
3.399 + */
3.400 +#include <string.h>
3.401 +#include "Array.h"
3.402 +#include "FixedArray.h"
3.403 +#include "Heap.h"
3.404 +#include "Zone.h"
3.405 +#include "Structures.h"
3.406 +#include "Heap-inl.h"
3.407 +
3.408 +using namespace ke;
3.409 +
3.410 +ArrayMap *
3.411 +ArrayMap::New(Zone *zone, Handle<ArrayType> type)
3.412 +{
3.413 + Local<Map> obj(zone, zone->allocateMap(MapKind_Array, sizeof(ArrayMap), MapKind_MetaArray));
3.414 + if (!obj)
3.415 + return NULL;
3.416 +
3.417 + Local<ArrayMap> map(zone, ArrayMap::cast(obj));
3.418 + map->type_ = type;
3.419 + return map;
3.420 +}
3.421 +
3.422 +ArrayMap *
3.423 +ArrayMap::NewDependent(Zone *zone, Handle<ArrayType> type)
3.424 +{
3.425 + Local<Map> obj(zone, zone->allocateMap(MapKind_DependentArray, sizeof(ArrayMap), MapKind_MetaArray));
3.426 + if (!obj)
3.427 + return NULL;
3.428 +
3.429 + Local<ArrayMap> map(zone, ArrayMap::cast(obj));
3.430 + map->type_ = type;
3.431 + return map;
3.432 +}
3.433 +
3.434 +Array *
3.435 +Array::NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure)
3.436 +{
3.437 + assert(!map->type()->isFixedLength() || nelements == map->type()->fixedLength());
3.438 +
3.439 + if (nelements > (INT_MAX / SizeForElement(map->type()))) {
3.440 + zone->reportError(Message_ArraySizeTooBig);
3.441 + return NULL;
3.442 + }
3.443 +
3.444 + size_t bytes = sizeof(Array);
3.445 + if (map->type()->hasInlineElements())
3.446 + bytes += SizeForElement(map->type()) * nelements;
3.447 +
3.448 + Local<Array> array(zone, Array::cast(zone->allocate(map, bytes, tenure)));
3.449 + if (!array)
3.450 + return NULL;
3.451 +
3.452 + array->length_ = 0;
3.453 + array->elements_ = NULL;
3.454 +
3.455 + if (map->type()->hasInlineElements()) {
3.456 + // This must be a fixed array containing no traceables.
3.457 + assert(nelements > 0);
3.458 + assert(map->type()->isFixedLength());
3.459 + assert(!map->type()->contained()->isTraceable());
3.460 +
3.461 + // Compute an interior |elements_| pointer, such that if elements_
3.462 + // is accessed like a FixedArray, we reach the appropriate vector.
3.463 + array->elements_ = Address((Array *)array + 1) - ByteArray::offsetToElements();
3.464 + array->length_ = nelements;
3.465 + memset(array->bytes(), 0, SizeForElement(map->type()) * nelements);
3.466 + return array;
3.467 + }
3.468 +
3.469 + // If there is nothing to allocate, we don't bother creating elements yet.
3.470 + if (!nelements)
3.471 + return array;
3.472 +
3.473 + if (!map->type()->contained()->isTraceable()) {
3.474 + size_t nbytes = SizeForElement(map->type()) * nelements;
3.475 + Local<ByteArray> elements(zone, ByteArray::New(zone, nbytes, tenure));
3.476 + if (!elements)
3.477 + return NULL;
3.478 +
3.479 + array->updateLengthAndElements(zone, nelements, elements);
3.480 + return array;
3.481 + }
3.482 +
3.483 + Local<FixedArray> elements(zone, FixedArray::New(zone, nelements, tenure));
3.484 + if (!elements)
3.485 + return NULL;
3.486 +
3.487 + array->updateLengthAndElements(zone, nelements, elements);
3.488 +
3.489 + // If this is an array of structs, we're required to allocate those structs now.
3.490 + if (map->type()->contained()->isStruct()) {
3.491 + Local<StructType> childType(zone, StructType::cast(map->type()->contained()));
3.492 + Local<StructMap> childMap(zone, childType->newMap());
3.493 + Local<Struct> child(zone);
3.494 + for (unsigned i = 0; i < nelements; i++) {
3.495 + child = Struct::New(zone, childMap, tenure);
3.496 + if (!child)
3.497 + return NULL;
3.498 +
3.499 + elements->set(zone, i, child);
3.500 + }
3.501 + }
3.502 +
3.503 + return array;
3.504 +}
3.505 +
3.506 +static Array *
3.507 +ConstructSizedArray(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH],
3.508 + unsigned level, Heap::Tenure tenure)
3.509 +{
3.510 + Local<Array> array(zone, Array::NewRaw(zone, map, dims[level], tenure));
3.511 + if (!array)
3.512 + return NULL;
3.513 +
3.514 + if (map->type()->contained()->isArray()) {
3.515 + Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
3.516 + Local<ArrayMap> childMap(zone, childType->newMap());
3.517 + Local<Array> child(zone);
3.518 +
3.519 + for (unsigned i = 0; i < unsigned(dims[level]); i++) {
3.520 + child = ConstructSizedArray(zone, childMap, dims, level + 1, tenure);
3.521 + if (!child)
3.522 + return NULL;
3.523 +
3.524 + array->writeObject(zone, i, child);
3.525 + }
3.526 + }
3.527 +
3.528 + return array;
3.529 +}
3.530 +
3.531 +Array *
3.532 +Array::NewSized(Zone *zone, Handle<ArrayMap> map, int dims[MAX_ARRAY_DEPTH], Heap::Tenure tenure)
3.533 +{
3.534 + for (size_t i = 0; i < map->type()->levels(); i++) {
3.535 + if (dims[i] < 0) {
3.536 + zone->reportError(Message_InvalidDimensionSize, dims[i], i);
3.537 + return NULL;
3.538 + }
3.539 + }
3.540 +
3.541 + return ConstructSizedArray(zone, map, dims, 0, tenure);
3.542 +}
3.543 +
3.544 +static Array *
3.545 +ConstructFixedArray(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
3.546 +{
3.547 + unsigned length = map->type()->fixedLength();
3.548 + Local<Array> array(zone, Array::NewRaw(zone, map, length, tenure));
3.549 + if (!array)
3.550 + return NULL;
3.551 +
3.552 + if (map->type()->contained()->isArray()) {
3.553 + Local<ArrayType> childType(zone, ArrayType::cast(map->type()->contained()));
3.554 + Local<ArrayMap> childMap(zone, childType->newMap());
3.555 + Local<Array> child(zone);
3.556 +
3.557 + if (childMap->type()->isFixedLength()) {
3.558 + for (unsigned i = 0; i < length; i++) {
3.559 + child = ConstructFixedArray(zone, childMap, tenure);
3.560 + if (!child)
3.561 + return NULL;
3.562 +
3.563 + array->writeObject(zone, i, child);
3.564 + }
3.565 + } else {
3.566 + for (unsigned i = 0; i < length; i++) {
3.567 + child = Array::NewRaw(zone, childMap, 0, tenure);
3.568 + if (!child)
3.569 + return NULL;
3.570 +
3.571 + array->writeObject(zone, i, child);
3.572 + }
3.573 + }
3.574 + }
3.575 +
3.576 + return array;
3.577 +}
3.578 +
3.579 +Array *
3.580 +Array::NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
3.581 +{
3.582 + return ConstructFixedArray(zone, map, tenure);
3.583 +}
3.584 +
3.585 +Array *
3.586 +Array::NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure tenure)
3.587 +{
3.588 + assert(map->type()->isCharArray());
3.589 +
3.590 + Local<Array> array(zone);
3.591 +
3.592 + if (map->type()->isFixedLength())
3.593 + array = Array::NewFixed(zone, map, tenure);
3.594 + else
3.595 + array = Array::New1D(zone, map, length + 1, tenure);
3.596 + if (!array)
3.597 + return NULL;
3.598 +
3.599 + assert(array->length() >= length + 1);
3.600 + memcpy(array->chars(), buffer, length + 1);
3.601 + return array;
3.602 +}
3.603 +
3.604 +Array *
3.605 +Array::New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure)
3.606 +{
3.607 + assert(map->type()->levels());
3.608 + return Array::NewRaw(zone, map, elements, tenure);
3.609 +}
3.610 +
3.611 +Array *
3.612 +Array::NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure)
3.613 +{
3.614 + assert(!map->type()->isFixedLength());
3.615 +
3.616 + return Array::NewRaw(zone, map, 0, tenure);
3.617 +}
3.618 +
3.619 +Array *
3.620 +Array::NewExternal(Zone *zone, Handle<ArrayMap> map, void *buffer, unsigned length,
3.621 + Heap::Tenure tenure)
3.622 +{
3.623 + Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
3.624 + if (!array)
3.625 + return NULL;
3.626 +
3.627 + array->length_ = length;
3.628 + array->elements_ = Address(buffer) - ByteArray::offsetToElements();
3.629 + return array;
3.630 +}
3.631 +
3.632 +static bool
3.633 +CopyArrayElements(Zone *zone, Handle<Type> contained, Handle<Array> dest, Handle<Array> source)
3.634 +{
3.635 + if (contained->isTraceable()) {
3.636 + if (contained->isStruct()) {
3.637 + assert(dest->type()->contained() == contained);
3.638 + assert(source->length() == dest->length());
3.639 +
3.640 + Local<Struct> left(zone);
3.641 + Local<Struct> right(zone);
3.642 + for (unsigned i = 0; i < source->length(); i++) {
3.643 + left = Struct::cast(dest->readObject(i));
3.644 + right = Struct::cast(source->readObject(i));
3.645 + if (!Struct::Copy(zone, left, right))
3.646 + return false;
3.647 + }
3.648 + } else if (contained->isArray() && ArrayType::cast(contained)->isFixedLength()) {
3.649 + assert(ArrayType::cast(source->type())->fixedLength() ==
3.650 + ArrayType::cast(contained)->fixedLength());
3.651 +
3.652 + Local<Array> left(zone);
3.653 + Local<Array> right(zone);
3.654 + for (unsigned i = 0; i < source->length(); i++) {
3.655 + left = Array::cast(dest->readObject(i));
3.656 + right = Array::cast(source->readObject(i));
3.657 + if (!Array::ShallowCopy(zone, left, right))
3.658 + return false;
3.659 + }
3.660 + } else {
3.661 + assert(dest->length() == source->length());
3.662 + for (unsigned i = 0; i < source->length(); i++)
3.663 + dest->writeObject(zone, i, source->readObject(i));
3.664 + }
3.665 + } else {
3.666 + assert(contained->pod() == dest->type()->contained()->pod());
3.667 + assert(contained->pod() == PrimitiveType_Char
3.668 + ? source->length() <= dest->length()
3.669 + : source->length() == dest->length());
3.670 +
3.671 + assert(dest->length());
3.672 + memcpy(dest->bytes(), source->bytes(), source->length() * Array::SizeForElement(dest->type()));
3.673 + }
3.674 + return true;
3.675 +}
3.676 +
3.677 +// Shallow copy an array. Fixed slots in the destination are copied from
3.678 +// the source, but otherwise, references are assigned.
3.679 +bool
3.680 +Array::ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source)
3.681 +{
3.682 + Local<Type> contained(zone, dest->type()->contained());
3.683 +
3.684 + return CopyArrayElements(zone, contained, dest, source);
3.685 +}
3.686 +
3.687 +Array *
3.688 +Array::DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure)
3.689 +{
3.690 + Local<ArrayMap> map(zone, ArrayMap::cast(source->map()));
3.691 +
3.692 + Local<Array> dest(zone, Array::NewRaw(zone, map, source->length(), tenure));
3.693 + if (!dest)
3.694 + return NULL;
3.695 +
3.696 + Local<Type> contained(zone, source->type()->contained());
3.697 + if (contained->isArray()) {
3.698 + assert(false);
3.699 + Local<Array> sub(zone);
3.700 + for (size_t i = 0; i < source->length(); i++) {
3.701 + sub = Array::cast(source->readObject(i));
3.702 + sub = DeepCopy(zone, sub, tenure);
3.703 + if (!sub)
3.704 + return NULL;
3.705 + dest->writeObject(zone, i, sub);
3.706 + }
3.707 + } else {
3.708 + if (!CopyArrayElements(zone, contained, dest, source))
3.709 + return NULL;
3.710 + }
3.711 +
3.712 + return dest;
3.713 +}
3.714 +
3.715 +Array *
3.716 +DependentArray::New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index)
3.717 +{
3.718 + Local<ArrayType> sourcetype(zone, source->type());
3.719 +
3.720 + // Right now we only support char arrays, to avoid nasty deep cloning
3.721 + // and to maybe cut off this feature as far as we can.
3.722 + assert(sourcetype->isCharArray());
3.723 + assert(map->type()->isCharArray());
3.724 +
3.725 + // We allow taking 0-length dependent strings. It's safe because any reads
3.726 + // or writes will fail.
3.727 + assert(index <= source->length());
3.728 +
3.729 + unsigned newlen = source->length() - index;
3.730 + unsigned eltsize = SizeForElement(sourcetype);
3.731 +
3.732 + if (!sourcetype->isFixedLength()) {
3.733 + // Simple case, just copy the array.
3.734 + Local<ArrayMap> map(zone, sourcetype->newMap());
3.735 +
3.736 + Local<Array> dest(zone, Array::NewRaw(zone, map, newlen, Heap::Tenure_Default));
3.737 + if (!dest)
3.738 + return NULL;
3.739 +
3.740 + memcpy(dest->bytes(),
3.741 + (Address)source->bytes() + (index * eltsize),
3.742 + newlen * eltsize);
3.743 + return dest;
3.744 + }
3.745 +
3.746 + Local<DependentArray> array(zone, DependentArray::cast(zone->allocate(map, sizeof(DependentArray), Heap::Tenure_Default)));
3.747 + if (!array)
3.748 + return NULL;
3.749 +
3.750 + // :GC: This is currently not safe for moving GC! Although we will mark
3.751 + // the object owning the interior pointer, the interior pointer could be
3.752 + // moved later. We will eventually need some way of dealing with this.
3.753 + Address elements = Address(source->bytes()) + (index * eltsize);
3.754 +
3.755 + array->root_ = source;
3.756 + array->length_ = newlen;
3.757 + array->elements_ = elements - ByteArray::offsetToElements();
3.758 + return array;
3.759 +}
4.1 --- a/src/Array.h Mon Jun 10 00:46:29 2013 +0100
4.2 +++ b/src/Array.h Mon Jun 10 01:04:43 2013 +0100
4.3 @@ -1,244 +1,244 @@
4.4 -/* vim: set ts=4 sw=4 tw=99 et:
4.5 - *
4.6 - * Copyright (C) 2012 David Anderson
4.7 - *
4.8 - * This file is part of SourcePawn.
4.9 - *
4.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
4.11 - * the terms of the GNU General Public License as published by the Free
4.12 - * Software Foundation, either version 3 of the License, or (at your option)
4.13 - * any later version.
4.14 - *
4.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
4.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
4.18 - *
4.19 - * You should have received a copy of the GNU General Public License along with
4.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
4.21 - */
4.22 -#ifndef _include_jitcraft_array_h_
4.23 -#define _include_jitcraft_array_h_
4.24 -
4.25 -#include "Heap.h"
4.26 -#include "Handles.h"
4.27 -#include "Types.h"
4.28 -#include "FixedArray.h"
4.29 -
4.30 -namespace ke {
4.31 -
4.32 -class ArrayMap;
4.33 -
4.34 -class Array : public Object
4.35 -{
4.36 - friend class ArrayMap;
4.37 -
4.38 - protected:
4.39 - // Note: we do not write barrier |elements_|, since it can be set to
4.40 - // arbitrary pointers.
4.41 - uint32 length_;
4.42 - union {
4.43 - void *elements_;
4.44 - Object *objelements_;
4.45 - };
4.46 -
4.47 - protected:
4.48 - void updateLengthAndElements(Zone *zone, unsigned length, Object *array) {
4.49 - length_ = length;
4.50 - write(zone, &objelements_, array);
4.51 - }
4.52 -
4.53 - public:
4.54 - static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
4.55 - static Array *NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
4.56 - static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
4.57 -
4.58 - static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
4.59 - static Array *NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
4.60 - static Array *NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure);
4.61 -
4.62 - static Array *NewExternal(Zone *zone,
4.63 - Handle<ArrayMap> map,
4.64 - void *buffer,
4.65 - unsigned length,
4.66 - Heap::Tenure tenure = Heap::Tenure_Default);
4.67 -
4.68 - // Copies an array from one reference to another, obeying language semantics.
4.69 - static bool ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source);
4.70 -
4.71 - // Creates a full duplicate of an array, following all array references as if
4.72 - // they were fixed. Array references inside structs or objects use ShallowCopy
4.73 - // semantics, as this is only intended for duplicating array literals, which
4.74 - // cannot contain structs.
4.75 - static Array *DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure);
4.76 -
4.77 - uint32 length() {
4.78 - return length_;
4.79 - }
4.80 -
4.81 - inline ArrayType *type();
4.82 -
4.83 - inline int *int32Vec();
4.84 - inline float *floatVec();
4.85 - inline char *chars();
4.86 - inline void *bytes();
4.87 -
4.88 - bool resize(Zone *zone, size_t newLength);
4.89 -
4.90 - static inline size_t SizeForElement(ArrayType *type) {
4.91 - if (type->contained()->isTraceable())
4.92 - return sizeof(ke::Object *);
4.93 - if (type->contained()->isInt32())
4.94 - return sizeof(int);
4.95 - if (type->contained()->primitive() == PrimitiveType_Char)
4.96 - return sizeof(char);
4.97 - assert(type->contained()->isFloat());
4.98 - return sizeof(float);
4.99 - }
4.100 -
4.101 - inline size_t objSize(ArrayMap *map);
4.102 -
4.103 - int readInt32(size_t index) {
4.104 - assert(index < length());
4.105 - return int32Vec()[index];
4.106 - }
4.107 - void writeInt32(size_t index, int i) {
4.108 - assert(index < length());
4.109 - int32Vec()[index] = i;
4.110 - }
4.111 - char readChar(size_t index) {
4.112 - assert(index < length());
4.113 - return chars()[index];
4.114 - }
4.115 - void writeChar(size_t index, char c) {
4.116 - assert(index < length());
4.117 - chars()[index] = c;
4.118 - }
4.119 - float readFloat(size_t index) {
4.120 - assert(index < length());
4.121 - return floatVec()[index];
4.122 - }
4.123 - void writeFloat(size_t index, float f) {
4.124 - assert(index < length());
4.125 - floatVec()[index] = f;
4.126 - }
4.127 - Object *readObject(size_t index) {
4.128 - return FixedArray::cast(objelements_)->at(index);
4.129 - }
4.130 - void writeObject(Zone *zone, size_t index, Object *ptr) {
4.131 - FixedArray::cast(objelements_)->set(zone, index, ptr);
4.132 - }
4.133 -
4.134 - // GC Descriptor.
4.135 - static inline size_t offsetOfElements() {
4.136 - return offsetof(Array, objelements_);
4.137 - }
4.138 - // End GC Descriptor.
4.139 -
4.140 - static Array *cast(Object *obj) {
4.141 - assert(!obj ||
4.142 - obj->is(MapKind_Array) ||
4.143 - obj->is(MapKind_DependentArray));
4.144 - return reinterpret_cast<Array *>(obj);
4.145 - }
4.146 -};
4.147 -
4.148 -class DependentArray : public Array
4.149 -{
4.150 - Barriered<Array> root_;
4.151 -
4.152 - public:
4.153 - static Array *New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index);
4.154 -
4.155 - // GC Descriptor.
4.156 - static inline size_t offsetOfRoot() {
4.157 - return offsetof(DependentArray, root_);
4.158 - }
4.159 - // End GC Descriptor.
4.160 -
4.161 - static DependentArray *cast(Object *obj) {
4.162 - assert(!obj || obj->is(MapKind_DependentArray));
4.163 - return reinterpret_cast<DependentArray *>(obj);
4.164 - }
4.165 -};
4.166 -
4.167 -class ArrayMap : public Map
4.168 -{
4.169 - Barriered<ArrayType> type_;
4.170 -
4.171 - public:
4.172 - static ArrayMap *New(Zone *zone, Handle<ArrayType> type);
4.173 -
4.174 - // DependentArray maps are never attached, and are just free-floating,
4.175 - // rooted ultimately by the bytecode. A :TODO: that we might need to
4.176 - // cache these, or attach them somewhere saner like ArrayType, which
4.177 - // itself will eventually be cached.
4.178 - static ArrayMap *NewDependent(Zone *zone, Handle<ArrayType> type);
4.179 -
4.180 - ArrayType *type() {
4.181 - return type_;
4.182 - }
4.183 -
4.184 - // GC Descriptor.
4.185 - static inline size_t offsetOfType() {
4.186 - return OFFSETOF(ArrayMap, type_);
4.187 - }
4.188 - // End GC Descriptor.
4.189 -
4.190 - static ArrayMap *cast(Object *obj) {
4.191 - assert(!obj || obj->is(MapKind_MetaArray));
4.192 - return reinterpret_cast<ArrayMap *>(obj);
4.193 - }
4.194 -};
4.195 -
4.196 -inline void *
4.197 -Array::bytes()
4.198 -{
4.199 - assert(!type()->contained()->isTraceable());
4.200 - assert(type()->hasInlineElements() ||
4.201 - type()->isExternalArray() ||
4.202 - is(MapKind_DependentArray) ||
4.203 - !length() ||
4.204 - ByteArray::cast((Object *)elements_));
4.205 -
4.206 - return Address(elements_) + ByteArray::offsetToElements();
4.207 -}
4.208 -
4.209 -inline int *
4.210 -Array::int32Vec()
4.211 -{
4.212 - assert(type()->contained()->isInt32());
4.213 - return reinterpret_cast<int *>(bytes());
4.214 -}
4.215 -
4.216 -inline float *
4.217 -Array::floatVec()
4.218 -{
4.219 - assert(type()->contained()->isFloat());
4.220 - return reinterpret_cast<float *>(bytes());
4.221 -}
4.222 -
4.223 -inline char *
4.224 -Array::chars()
4.225 -{
4.226 - assert(type()->isCharArray());
4.227 - return reinterpret_cast<char *>(bytes());
4.228 -}
4.229 -
4.230 -inline ArrayType *
4.231 -Array::type()
4.232 -{
4.233 - return ArrayMap::cast(map())->type();
4.234 -}
4.235 -
4.236 -inline size_t
4.237 -Array::objSize(ArrayMap *map)
4.238 -{
4.239 - assert(this->map() == map);
4.240 - if (map->type()->hasInlineElements())
4.241 - return sizeof(Array) + Array::SizeForElement(map->type()) * length();
4.242 - return sizeof(Array);
4.243 -}
4.244 -
4.245 -}
4.246 -
4.247 -#endif // _include_jitcraft_array_h_
4.248 +/* vim: set ts=4 sw=4 tw=99 et:
4.249 + *
4.250 + * Copyright (C) 2012 David Anderson
4.251 + *
4.252 + * This file is part of SourcePawn.
4.253 + *
4.254 + * SourcePawn is free software: you can redistribute it and/or modify it under
4.255 + * the terms of the GNU General Public License as published by the Free
4.256 + * Software Foundation, either version 3 of the License, or (at your option)
4.257 + * any later version.
4.258 + *
4.259 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
4.260 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
4.261 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
4.262 + *
4.263 + * You should have received a copy of the GNU General Public License along with
4.264 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
4.265 + */
4.266 +#ifndef _include_jitcraft_array_h_
4.267 +#define _include_jitcraft_array_h_
4.268 +
4.269 +#include "Heap.h"
4.270 +#include "Handles.h"
4.271 +#include "Types.h"
4.272 +#include "FixedArray.h"
4.273 +
4.274 +namespace ke {
4.275 +
4.276 +class ArrayMap;
4.277 +
4.278 +class Array : public Object
4.279 +{
4.280 + friend class ArrayMap;
4.281 +
4.282 + protected:
4.283 + // Note: we do not write barrier |elements_|, since it can be set to
4.284 + // arbitrary pointers.
4.285 + uint32 length_;
4.286 + union {
4.287 + void *elements_;
4.288 + Object *objelements_;
4.289 + };
4.290 +
4.291 + protected:
4.292 + void updateLengthAndElements(Zone *zone, unsigned length, Object *array) {
4.293 + length_ = length;
4.294 + write(zone, &objelements_, array);
4.295 + }
4.296 +
4.297 + public:
4.298 + static Array *NewFixed(Zone *zone, Handle<ArrayMap> map, Heap::Tenure = Heap::Tenure_Default);
4.299 + static Array *NewString(Zone *zone, Handle<ArrayMap> map, char *buffer, size_t length, Heap::Tenure = Heap::Tenure_Default);
4.300 + static Array *NewSized(Zone *zone, Handle<ArrayMap> map, int sizes[MAX_ARRAY_DEPTH], Heap::Tenure = Heap::Tenure_Default);
4.301 +
4.302 + static Array *New1D(Zone *zone, Handle<ArrayMap> map, uint32 elements, Heap::Tenure tenure = Heap::Tenure_Default);
4.303 + static Array *NewEmpty(Zone *zone, Handle<ArrayMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
4.304 + static Array *NewRaw(Zone *zone, Handle<ArrayMap> map, unsigned nelements, Heap::Tenure tenure);
4.305 +
4.306 + static Array *NewExternal(Zone *zone,
4.307 + Handle<ArrayMap> map,
4.308 + void *buffer,
4.309 + unsigned length,
4.310 + Heap::Tenure tenure = Heap::Tenure_Default);
4.311 +
4.312 + // Copies an array from one reference to another, obeying language semantics.
4.313 + static bool ShallowCopy(Zone *zone, Handle<Array> dest, Handle<Array> source);
4.314 +
4.315 + // Creates a full duplicate of an array, following all array references as if
4.316 + // they were fixed. Array references inside structs or objects use ShallowCopy
4.317 + // semantics, as this is only intended for duplicating array literals, which
4.318 + // cannot contain structs.
4.319 + static Array *DeepCopy(Zone *zone, Handle<Array> source, Heap::Tenure tenure);
4.320 +
4.321 + uint32 length() {
4.322 + return length_;
4.323 + }
4.324 +
4.325 + inline ArrayType *type();
4.326 +
4.327 + inline int *int32Vec();
4.328 + inline float *floatVec();
4.329 + inline char *chars();
4.330 + inline void *bytes();
4.331 +
4.332 + bool resize(Zone *zone, size_t newLength);
4.333 +
4.334 + static inline size_t SizeForElement(ArrayType *type) {
4.335 + if (type->contained()->isTraceable())
4.336 + return sizeof(ke::Object *);
4.337 + if (type->contained()->isInt32())
4.338 + return sizeof(int);
4.339 + if (type->contained()->primitive() == PrimitiveType_Char)
4.340 + return sizeof(char);
4.341 + assert(type->contained()->isFloat());
4.342 + return sizeof(float);
4.343 + }
4.344 +
4.345 + inline size_t objSize(ArrayMap *map);
4.346 +
4.347 + int readInt32(size_t index) {
4.348 + assert(index < length());
4.349 + return int32Vec()[index];
4.350 + }
4.351 + void writeInt32(size_t index, int i) {
4.352 + assert(index < length());
4.353 + int32Vec()[index] = i;
4.354 + }
4.355 + char readChar(size_t index) {
4.356 + assert(index < length());
4.357 + return chars()[index];
4.358 + }
4.359 + void writeChar(size_t index, char c) {
4.360 + assert(index < length());
4.361 + chars()[index] = c;
4.362 + }
4.363 + float readFloat(size_t index) {
4.364 + assert(index < length());
4.365 + return floatVec()[index];
4.366 + }
4.367 + void writeFloat(size_t index, float f) {
4.368 + assert(index < length());
4.369 + floatVec()[index] = f;
4.370 + }
4.371 + Object *readObject(size_t index) {
4.372 + return FixedArray::cast(objelements_)->at(index);
4.373 + }
4.374 + void writeObject(Zone *zone, size_t index, Object *ptr) {
4.375 + FixedArray::cast(objelements_)->set(zone, index, ptr);
4.376 + }
4.377 +
4.378 + // GC Descriptor.
4.379 + static inline size_t offsetOfElements() {
4.380 + return offsetof(Array, objelements_);
4.381 + }
4.382 + // End GC Descriptor.
4.383 +
4.384 + static Array *cast(Object *obj) {
4.385 + assert(!obj ||
4.386 + obj->is(MapKind_Array) ||
4.387 + obj->is(MapKind_DependentArray));
4.388 + return reinterpret_cast<Array *>(obj);
4.389 + }
4.390 +};
4.391 +
4.392 +class DependentArray : public Array
4.393 +{
4.394 + Barriered<Array> root_;
4.395 +
4.396 + public:
4.397 + static Array *New(Zone *zone, Handle<Array> source, Handle<ArrayMap> map, unsigned index);
4.398 +
4.399 + // GC Descriptor.
4.400 + static inline size_t offsetOfRoot() {
4.401 + return offsetof(DependentArray, root_);
4.402 + }
4.403 + // End GC Descriptor.
4.404 +
4.405 + static DependentArray *cast(Object *obj) {
4.406 + assert(!obj || obj->is(MapKind_DependentArray));
4.407 + return reinterpret_cast<DependentArray *>(obj);
4.408 + }
4.409 +};
4.410 +
4.411 +class ArrayMap : public Map
4.412 +{
4.413 + Barriered<ArrayType> type_;
4.414 +
4.415 + public:
4.416 + static ArrayMap *New(Zone *zone, Handle<ArrayType> type);
4.417 +
4.418 + // DependentArray maps are never attached, and are just free-floating,
4.419 + // rooted ultimately by the bytecode. A :TODO: that we might need to
4.420 + // cache these, or attach them somewhere saner like ArrayType, which
4.421 + // itself will eventually be cached.
4.422 + static ArrayMap *NewDependent(Zone *zone, Handle<ArrayType> type);
4.423 +
4.424 + ArrayType *type() {
4.425 + return type_;
4.426 + }
4.427 +
4.428 + // GC Descriptor.
4.429 + static inline size_t offsetOfType() {
4.430 + return OFFSETOF(ArrayMap, type_);
4.431 + }
4.432 + // End GC Descriptor.
4.433 +
4.434 + static ArrayMap *cast(Object *obj) {
4.435 + assert(!obj || obj->is(MapKind_MetaArray));
4.436 + return reinterpret_cast<ArrayMap *>(obj);
4.437 + }
4.438 +};
4.439 +
4.440 +inline void *
4.441 +Array::bytes()
4.442 +{
4.443 + assert(!type()->contained()->isTraceable());
4.444 + assert(type()->hasInlineElements() ||
4.445 + type()->isExternalArray() ||
4.446 + is(MapKind_DependentArray) ||
4.447 + !length() ||
4.448 + ByteArray::cast((Object *)elements_));
4.449 +
4.450 + return Address(elements_) + ByteArray::offsetToElements();
4.451 +}
4.452 +
4.453 +inline int *
4.454 +Array::int32Vec()
4.455 +{
4.456 + assert(type()->contained()->isInt32());
4.457 + return reinterpret_cast<int *>(bytes());
4.458 +}
4.459 +
4.460 +inline float *
4.461 +Array::floatVec()
4.462 +{
4.463 + assert(type()->contained()->isFloat());
4.464 + return reinterpret_cast<float *>(bytes());
4.465 +}
4.466 +
4.467 +inline char *
4.468 +Array::chars()
4.469 +{
4.470 + assert(type()->isCharArray());
4.471 + return reinterpret_cast<char *>(bytes());
4.472 +}
4.473 +
4.474 +inline ArrayType *
4.475 +Array::type()
4.476 +{
4.477 + return ArrayMap::cast(map())->type();
4.478 +}
4.479 +
4.480 +inline size_t
4.481 +Array::objSize(ArrayMap *map)
4.482 +{
4.483 + assert(this->map() == map);
4.484 + if (map->type()->hasInlineElements())
4.485 + return sizeof(Array) + Array::SizeForElement(map->type()) * length();
4.486 + return sizeof(Array);
4.487 +}
4.488 +
4.489 +}
4.490 +
4.491 +#endif // _include_jitcraft_array_h_
5.1 --- a/src/Code.h Mon Jun 10 00:46:29 2013 +0100
5.2 +++ b/src/Code.h Mon Jun 10 01:04:43 2013 +0100
5.3 @@ -1,140 +1,140 @@
5.4 -/* vim: set ts=4 sw=4 tw=99 et:
5.5 - *
5.6 - * Copyright (C) 2012 David Anderson
5.7 - *
5.8 - * This file is part of JITCraft.
5.9 - *
5.10 - * JITCraft is free software: you can redistribute it and/or modify it under
5.11 - * the terms of the GNU General Public License as published by the Free
5.12 - * Software Foundation, either version 3 of the License, or (at your option)
5.13 - * any later version.
5.14 - *
5.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
5.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5.18 - *
5.19 - * You should have received a copy of the GNU General Public License along with
5.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
5.21 - */
5.22 -#ifndef _include_jc_code_h_
5.23 -#define _include_jc_code_h_
5.24 -
5.25 -#include "Opcodes.h"
5.26 -#include "Barriers.h"
5.27 -#include "Heap.h"
5.28 -#include "Types.h"
5.29 -#include "FixedArray.h"
5.30 -
5.31 -namespace ke {
5.32 -
5.33 -class Module;
5.34 -class Type;
5.35 -
5.36 -// A code object contains the bytecode compiled from a function (or global
5.37 -// script), as well as all information needed to interpret or JIT-compile
5.38 -// the bytecode.
5.39 -class Code : public Object
5.40 -{
5.41 - Barriered<Module> module_;
5.42 - Barriered<ByteArray> bytecode_;
5.43 - Barriered<FixedArray> locals_;
5.44 - Barriered<FixedArray> objects_;
5.45 - Barriered<FixedArray> strings_;
5.46 - Barriered<ByteArray> safepoints_;
5.47 - Barriered<ByteArray> sourcemap_;
5.48 - unsigned maxStackDepth_;
5.49 - unsigned lineNumber_;
5.50 - unsigned maxLoopDepth_;
5.51 -
5.52 - public:
5.53 - static inline size_t BytesPerSafepoint(size_t stackDepth) {
5.54 - return (Align(stackDepth, 8) / 8) + sizeof(unsigned);
5.55 - }
5.56 -
5.57 - public:
5.58 - static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
5.59 - Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
5.60 - unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);
5.61 -
5.62 - Module *module() {
5.63 - return module_;
5.64 - }
5.65 - bytecode *start() {
5.66 - return bytecode_->raw();
5.67 - }
5.68 - unsigned length() {
5.69 - return bytecode_->length();
5.70 - }
5.71 - Type *localType(size_t index) {
5.72 - return Type::cast(locals_->at(index));
5.73 - }
5.74 - unsigned nlocals() {
5.75 - return locals_ ? locals_->length() : 0;
5.76 - }
5.77 - unsigned maxStackDepth() {
5.78 - return maxStackDepth_;
5.79 - }
5.80 - unsigned maxLoopDepth() {
5.81 - return maxLoopDepth_;
5.82 - }
5.83 - Map *map(size_t index) {
5.84 - return Map::cast(objects_->at(index));
5.85 - }
5.86 - Object *object(size_t index) {
5.87 - return objects_->at(index);
5.88 - }
5.89 - ByteArray *safepoints() {
5.90 - return safepoints_;
5.91 - }
5.92 - FixedArray *strings() {
5.93 - return strings_;
5.94 - }
5.95 - uint8 *safepointAt(unsigned pcOffset);
5.96 -
5.97 - void setModule(Handle<Module> module) {
5.98 - module_ = module;
5.99 - }
5.100 -
5.101 - unsigned pcToOffset(bytecode *pc) {
5.102 - assert(pc >= start() && pc < start() + length());
5.103 - return unsigned(pc - start());
5.104 - }
5.105 -
5.106 - SourcePosition pcToSource(unsigned pc);
5.107 - unsigned lineNumber() {
5.108 - return lineNumber_;
5.109 - }
5.110 -
5.111 - // GC Descriptor.
5.112 - static inline size_t offsetOfModule() {
5.113 - return OFFSETOF(Code, module_);
5.114 - }
5.115 - static inline size_t offsetOfBytecode() {
5.116 - return OFFSETOF(Code, bytecode_);
5.117 - }
5.118 - static inline size_t offsetOfLocals() {
5.119 - return OFFSETOF(Code, locals_);
5.120 - }
5.121 - static inline size_t offsetOfObjects() {
5.122 - return OFFSETOF(Code, objects_);
5.123 - }
5.124 - static inline size_t offsetOfStrings() {
5.125 - return OFFSETOF(Code, strings_);
5.126 - }
5.127 - static inline size_t offsetOfSafepoints() {
5.128 - return OFFSETOF(Code, safepoints_);
5.129 - }
5.130 - static inline size_t offsetOfSourceMap() {
5.131 - return OFFSETOF(Code, sourcemap_);
5.132 - }
5.133 - // End GC Descriptor.
5.134 -
5.135 - static Code *cast(Object *obj) {
5.136 - assert(!obj || obj->is(MapKind_Code));
5.137 - return reinterpret_cast<Code *>(obj);
5.138 - }
5.139 -};
5.140 -
5.141 -}
5.142 -
5.143 -#endif // _include_jc_code_h_
5.144 +/* vim: set ts=4 sw=4 tw=99 et:
5.145 + *
5.146 + * Copyright (C) 2012 David Anderson
5.147 + *
5.148 + * This file is part of JITCraft.
5.149 + *
5.150 + * JITCraft is free software: you can redistribute it and/or modify it under
5.151 + * the terms of the GNU General Public License as published by the Free
5.152 + * Software Foundation, either version 3 of the License, or (at your option)
5.153 + * any later version.
5.154 + *
5.155 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
5.156 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.157 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5.158 + *
5.159 + * You should have received a copy of the GNU General Public License along with
5.160 + * JITCraft. If not, see http://www.gnu.org/licenses/.
5.161 + */
5.162 +#ifndef _include_jc_code_h_
5.163 +#define _include_jc_code_h_
5.164 +
5.165 +#include "Opcodes.h"
5.166 +#include "Barriers.h"
5.167 +#include "Heap.h"
5.168 +#include "Types.h"
5.169 +#include "FixedArray.h"
5.170 +
5.171 +namespace ke {
5.172 +
5.173 +class Module;
5.174 +class Type;
5.175 +
5.176 +// A code object contains the bytecode compiled from a function (or global
5.177 +// script), as well as all information needed to interpret or JIT-compile
5.178 +// the bytecode.
5.179 +class Code : public Object
5.180 +{
5.181 + Barriered<Module> module_;
5.182 + Barriered<ByteArray> bytecode_;
5.183 + Barriered<FixedArray> locals_;
5.184 + Barriered<FixedArray> objects_;
5.185 + Barriered<FixedArray> strings_;
5.186 + Barriered<ByteArray> safepoints_;
5.187 + Barriered<ByteArray> sourcemap_;
5.188 + unsigned maxStackDepth_;
5.189 + unsigned lineNumber_;
5.190 + unsigned maxLoopDepth_;
5.191 +
5.192 + public:
5.193 + static inline size_t BytesPerSafepoint(size_t stackDepth) {
5.194 + return (Align(stackDepth, 8) / 8) + sizeof(unsigned);
5.195 + }
5.196 +
5.197 + public:
5.198 + static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
5.199 + Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
5.200 + unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);
5.201 +
5.202 + Module *module() {
5.203 + return module_;
5.204 + }
5.205 + bytecode *start() {
5.206 + return bytecode_->raw();
5.207 + }
5.208 + unsigned length() {
5.209 + return bytecode_->length();
5.210 + }
5.211 + Type *localType(size_t index) {
5.212 + return Type::cast(locals_->at(index));
5.213 + }
5.214 + unsigned nlocals() {
5.215 + return locals_ ? locals_->length() : 0;
5.216 + }
5.217 + unsigned maxStackDepth() {
5.218 + return maxStackDepth_;
5.219 + }
5.220 + unsigned maxLoopDepth() {
5.221 + return maxLoopDepth_;
5.222 + }
5.223 + Map *map(size_t index) {
5.224 + return Map::cast(objects_->at(index));
5.225 + }
5.226 + Object *object(size_t index) {
5.227 + return objects_->at(index);
5.228 + }
5.229 + ByteArray *safepoints() {
5.230 + return safepoints_;
5.231 + }
5.232 + FixedArray *strings() {
5.233 + return strings_;
5.234 + }
5.235 + uint8 *safepointAt(unsigned pcOffset);
5.236 +
5.237 + void setModule(Handle<Module> module) {
5.238 + module_ = module;
5.239 + }
5.240 +
5.241 + unsigned pcToOffset(bytecode *pc) {
5.242 + assert(pc >= start() && pc < start() + length());
5.243 + return unsigned(pc - start());
5.244 + }
5.245 +
5.246 + SourcePosition pcToSource(unsigned pc);
5.247 + unsigned lineNumber() {
5.248 + return lineNumber_;
5.249 + }
5.250 +
5.251 + // GC Descriptor.
5.252 + static inline size_t offsetOfModule() {
5.253 + return OFFSETOF(Code, module_);
5.254 + }
5.255 + static inline size_t offsetOfBytecode() {
5.256 + return OFFSETOF(Code, bytecode_);
5.257 + }
5.258 + static inline size_t offsetOfLocals() {
5.259 + return OFFSETOF(Code, locals_);
5.260 + }
5.261 + static inline size_t offsetOfObjects() {
5.262 + return OFFSETOF(Code, objects_);
5.263 + }
5.264 + static inline size_t offsetOfStrings() {
5.265 + return OFFSETOF(Code, strings_);
5.266 + }
5.267 + static inline size_t offsetOfSafepoints() {
5.268 + return OFFSETOF(Code, safepoints_);
5.269 + }
5.270 + static inline size_t offsetOfSourceMap() {
5.271 + return OFFSETOF(Code, sourcemap_);
5.272 + }
5.273 + // End GC Descriptor.
5.274 +
5.275 + static Code *cast(Object *obj) {
5.276 + assert(!obj || obj->is(MapKind_Code));
5.277 + return reinterpret_cast<Code *>(obj);
5.278 + }
5.279 +};
5.280 +
5.281 +}
5.282 +
5.283 +#endif // _include_jc_code_h_
6.1 --- a/src/CompactBuffer.h Mon Jun 10 00:46:29 2013 +0100
6.2 +++ b/src/CompactBuffer.h Mon Jun 10 01:04:43 2013 +0100
6.3 @@ -1,100 +1,100 @@
6.4 -/* vim: set ts=4 sw=4 tw=99 et:
6.5 - *
6.6 - * Copyright (C) 2012 David Anderson
6.7 - *
6.8 - * This file is part of JITCraft.
6.9 - *
6.10 - * JITCraft is free software: you can redistribute it and/or modify it under
6.11 - * the terms of the GNU General Public License as published by the Free
6.12 - * Software Foundation, either version 3 of the License, or (at your option)
6.13 - * any later version.
6.14 - *
6.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
6.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
6.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6.18 - *
6.19 - * You should have received a copy of the GNU General Public License along with
6.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
6.21 - */
6.22 -#ifndef _include_jc_compact_buffer_h_
6.23 -#define _include_jc_compact_buffer_h_
6.24 -
6.25 -#include "AllocatorPolicies.h"
6.26 -#include "Utility.h"
6.27 -#include "Vector.h"
6.28 -
6.29 -namespace ke {
6.30 -
6.31 -class CompactBufferReader
6.32 -{
6.33 - const uint8 *pos_;
6.34 - const uint8 *end_;
6.35 -
6.36 - public:
6.37 - CompactBufferReader(const uint8 *start, const uint8 *end)
6.38 - : pos_(start),
6.39 - end_(end)
6.40 - {
6.41 - }
6.42 -
6.43 - uint8 readUint8() {
6.44 - assert(pos_ < end_);
6.45 - return *pos_++;
6.46 - }
6.47 -
6.48 - uint32 readUint32() {
6.49 - uint32 value = 0;
6.50 - uint32 shift = 0;
6.51 -
6.52 - uint8 byte;
6.53 - do {
6.54 - byte = readUint8();
6.55 - value |= (byte >> 1) << shift;
6.56 - shift += 7;
6.57 - } while (byte & 1);
6.58 -
6.59 - assert(shift < 32);
6.60 - return value;
6.61 - }
6.62 -
6.63 - bool done() const {
6.64 - return pos_ == end_;
6.65 - }
6.66 -};
6.67 -
6.68 -class CompactBufferWriter
6.69 -{
6.70 - Vector<uint8, ZoneAllocatorPolicy> buffer_;
6.71 - bool enoughMemory_;
6.72 -
6.73 - public:
6.74 - CompactBufferWriter()
6.75 - : enoughMemory_(true)
6.76 - {
6.77 - }
6.78 -
6.79 - void writeUint8(unsigned value) {
6.80 - enoughMemory_ &= buffer_.append(value);
6.81 - }
6.82 - void writeUint32(unsigned value) {
6.83 - do {
6.84 - writeUint8(((value & 0x7F) << 1) | (value > 0x7F));
6.85 - value >>= 7;
6.86 - } while (value);
6.87 - }
6.88 -
6.89 - uint8 *buffer() const {
6.90 - return buffer_.buffer();
6.91 - }
6.92 - size_t length() const {
6.93 - return buffer_.length();
6.94 - }
6.95 -
6.96 - bool oom() const {
6.97 - return !enoughMemory_;
6.98 - }
6.99 -};
6.100 -
6.101 -}
6.102 -
6.103 -#endif // _include_jc_compact_buffer_h_
6.104 +/* vim: set ts=4 sw=4 tw=99 et:
6.105 + *
6.106 + * Copyright (C) 2012 David Anderson
6.107 + *
6.108 + * This file is part of JITCraft.
6.109 + *
6.110 + * JITCraft is free software: you can redistribute it and/or modify it under
6.111 + * the terms of the GNU General Public License as published by the Free
6.112 + * Software Foundation, either version 3 of the License, or (at your option)
6.113 + * any later version.
6.114 + *
6.115 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
6.116 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
6.117 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6.118 + *
6.119 + * You should have received a copy of the GNU General Public License along with
6.120 + * JITCraft. If not, see http://www.gnu.org/licenses/.
6.121 + */
6.122 +#ifndef _include_jc_compact_buffer_h_
6.123 +#define _include_jc_compact_buffer_h_
6.124 +
6.125 +#include "AllocatorPolicies.h"
6.126 +#include "Utility.h"
6.127 +#include "Vector.h"
6.128 +
6.129 +namespace ke {
6.130 +
6.131 +class CompactBufferReader
6.132 +{
6.133 + const uint8 *pos_;
6.134 + const uint8 *end_;
6.135 +
6.136 + public:
6.137 + CompactBufferReader(const uint8 *start, const uint8 *end)
6.138 + : pos_(start),
6.139 + end_(end)
6.140 + {
6.141 + }
6.142 +
6.143 + uint8 readUint8() {
6.144 + assert(pos_ < end_);
6.145 + return *pos_++;
6.146 + }
6.147 +
6.148 + uint32 readUint32() {
6.149 + uint32 value = 0;
6.150 + uint32 shift = 0;
6.151 +
6.152 + uint8 byte;
6.153 + do {
6.154 + byte = readUint8();
6.155 + value |= (byte >> 1) << shift;
6.156 + shift += 7;
6.157 + } while (byte & 1);
6.158 +
6.159 + assert(shift < 32);
6.160 + return value;
6.161 + }
6.162 +
6.163 + bool done() const {
6.164 + return pos_ == end_;
6.165 + }
6.166 +};
6.167 +
6.168 +class CompactBufferWriter
6.169 +{
6.170 + Vector<uint8, ZoneAllocatorPolicy> buffer_;
6.171 + bool enoughMemory_;
6.172 +
6.173 + public:
6.174 + CompactBufferWriter()
6.175 + : enoughMemory_(true)
6.176 + {
6.177 + }
6.178 +
6.179 + void writeUint8(unsigned value) {
6.180 + enoughMemory_ &= buffer_.append(value);
6.181 + }
6.182 + void writeUint32(unsigned value) {
6.183 + do {
6.184 + writeUint8(((value & 0x7F) << 1) | (value > 0x7F));
6.185 + value >>= 7;
6.186 + } while (value);
6.187 + }
6.188 +
6.189 + uint8 *buffer() const {
6.190 + return buffer_.buffer();
6.191 + }
6.192 + size_t length() const {
6.193 + return buffer_.length();
6.194 + }
6.195 +
6.196 + bool oom() const {
6.197 + return !enoughMemory_;
6.198 + }
6.199 +};
6.200 +
6.201 +}
6.202 +
6.203 +#endif // _include_jc_compact_buffer_h_
7.1 --- a/src/Environments.cpp Mon Jun 10 00:46:29 2013 +0100
7.2 +++ b/src/Environments.cpp Mon Jun 10 01:04:43 2013 +0100
7.3 @@ -1,102 +1,102 @@
7.4 -/*
7.5 - * Copyright (C) 2012 David Anderson
7.6 - *
7.7 - * This file is part of SourcePawn.
7.8 - *
7.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
7.10 - * the terms of the GNU General Public License as published by the Free
7.11 - * Software Foundation, either version 3 of the License, or (at your option)
7.12 - * any later version.
7.13 - *
7.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
7.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
7.17 - *
7.18 - * You should have received a copy of the GNU General Public License along with
7.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
7.20 - */
7.21 -#include <string.h>
7.22 -#include "Utility.h"
7.23 -#include "Environments.h"
7.24 -#include "Structures.h"
7.25 -#include "FixedArray.h"
7.26 -#include "Zone.h"
7.27 -#include "compiler/NameBinding.h"
7.28 -#include "Spaces-inl.h"
7.29 -#include "Heap-inl.h"
7.30 -
7.31 -using namespace ke;
7.32 -
7.33 -EnvironmentSlotDescriptorArray *
7.34 -EnvironmentSlotDescriptorArray::New(Zone *zone, unsigned nslots)
7.35 -{
7.36 - size_t bytesNeeded = sizeof(EnvironmentSlotDescriptorArray) +
7.37 - sizeof(EnvironmentSlotDescriptor) * nslots;
7.38 -
7.39 - Local<EnvironmentSlotDescriptorArray> array(zone);
7.40 - Local<Map> map(zone, zone->getMap(MapKind_EnvironmentSlotDescriptorArray));
7.41 -
7.42 - array = EnvironmentSlotDescriptorArray::cast(zone->allocate(map, bytesNeeded, Heap::Tenure_Old));
7.43 - if (!array)
7.44 - return NULL;
7.45 -
7.46 - // We zero the array for safety, since we could GC or fail before initialization.
7.47 - array->length_ = nslots;
7.48 - memset(array->slots(), 0, sizeof(EnvironmentSlotDescriptor) * nslots);
7.49 - return array;
7.50 -}
7.51 -
7.52 -Environment *
7.53 -Environment::New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure)
7.54 -{
7.55 - size_t bytesNeeded = sizeof(Environment) + map->structureSize();
7.56 - Local<Environment> env(zone, Environment::cast(zone->allocate(map, bytesNeeded, tenure)));
7.57 - if (!env)
7.58 - return NULL;
7.59 -
7.60 - // Initialize when called from C++, to make sure object slots are NULL.
7.61 - memset((Object *)env + 1, 0, map->structureSize());
7.62 - return env;
7.63 -}
7.64 -
7.65 -#if 0
7.66 -EnvironmentMap *
7.67 -EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
7.68 -{
7.69 - StructureBufferBuilder structure;
7.70 -
7.71 - Local<EnvironmentSlotDescriptorArray> slots(zone);
7.72 - slots = EnvironmentSlotDescriptorArray::New(zone, nvars);
7.73 - if (!slots)
7.74 - return NULL;
7.75 -
7.76 - // Build the descriptor table, mapping each slot to an offset and type.
7.77 - Local<Type> type(zone);
7.78 - for (unsigned i = 0; i < nvars; i++) {
7.79 - assert(vars[i]->slot() == i);
7.80 - type = vars[i]->type();
7.81 -
7.82 - EnvironmentSlotDescriptor &desc = slots->slots()[i];
7.83 - if (!structure.add(type, &desc.offset))
7.84 - return NULL;
7.85 -
7.86 - desc.type = type;
7.87 - }
7.88 -
7.89 - // Allocate the actual map now.
7.90 - size_t bytesNeeded = sizeof(EnvironmentMap) + structure.traceableOffsetCount() * sizeof(unsigned);
7.91 -
7.92 - Local<EnvironmentMap> map(zone);
7.93 - map = EnvironmentMap::cast(zone->allocateMap(MapKind_Environment, bytesNeeded, MapKind_MetaEnvironment));
7.94 - if (!map)
7.95 - return NULL;
7.96 -
7.97 - // Fill in the map fields, and copy the traceable offsets structure.
7.98 - map->structureSize_ = structure.structureSize();
7.99 - map->traceOffsetCount_ = structure.traceableOffsetCount();
7.100 - map->slots_ = slots;
7.101 - memcpy(const_cast<unsigned *>(map->traceOffsets()), structure.offsets(), sizeof(unsigned) * structure.traceableOffsetCount());
7.102 -
7.103 - return map;
7.104 -}
7.105 +/*
7.106 + * Copyright (C) 2012 David Anderson
7.107 + *
7.108 + * This file is part of SourcePawn.
7.109 + *
7.110 + * SourcePawn is free software: you can redistribute it and/or modify it under
7.111 + * the terms of the GNU General Public License as published by the Free
7.112 + * Software Foundation, either version 3 of the License, or (at your option)
7.113 + * any later version.
7.114 + *
7.115 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
7.116 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7.117 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
7.118 + *
7.119 + * You should have received a copy of the GNU General Public License along with
7.120 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
7.121 + */
7.122 +#include <string.h>
7.123 +#include "Utility.h"
7.124 +#include "Environments.h"
7.125 +#include "Structures.h"
7.126 +#include "FixedArray.h"
7.127 +#include "Zone.h"
7.128 +#include "compiler/NameBinding.h"
7.129 +#include "Spaces-inl.h"
7.130 +#include "Heap-inl.h"
7.131 +
7.132 +using namespace ke;
7.133 +
7.134 +EnvironmentSlotDescriptorArray *
7.135 +EnvironmentSlotDescriptorArray::New(Zone *zone, unsigned nslots)
7.136 +{
7.137 + size_t bytesNeeded = sizeof(EnvironmentSlotDescriptorArray) +
7.138 + sizeof(EnvironmentSlotDescriptor) * nslots;
7.139 +
7.140 + Local<EnvironmentSlotDescriptorArray> array(zone);
7.141 + Local<Map> map(zone, zone->getMap(MapKind_EnvironmentSlotDescriptorArray));
7.142 +
7.143 + array = EnvironmentSlotDescriptorArray::cast(zone->allocate(map, bytesNeeded, Heap::Tenure_Old));
7.144 + if (!array)
7.145 + return NULL;
7.146 +
7.147 + // We zero the array for safety, since we could GC or fail before initialization.
7.148 + array->length_ = nslots;
7.149 + memset(array->slots(), 0, sizeof(EnvironmentSlotDescriptor) * nslots);
7.150 + return array;
7.151 +}
7.152 +
7.153 +Environment *
7.154 +Environment::New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure)
7.155 +{
7.156 + size_t bytesNeeded = sizeof(Environment) + map->structureSize();
7.157 + Local<Environment> env(zone, Environment::cast(zone->allocate(map, bytesNeeded, tenure)));
7.158 + if (!env)
7.159 + return NULL;
7.160 +
7.161 + // Initialize when called from C++, to make sure object slots are NULL.
7.162 + memset((Object *)env + 1, 0, map->structureSize());
7.163 + return env;
7.164 +}
7.165 +
7.166 +#if 0
7.167 +EnvironmentMap *
7.168 +EnvironmentMap::New(Zone *zone, unsigned nvars, Variable **vars)
7.169 +{
7.170 + StructureBufferBuilder structure;
7.171 +
7.172 + Local<EnvironmentSlotDescriptorArray> slots(zone);
7.173 + slots = EnvironmentSlotDescriptorArray::New(zone, nvars);
7.174 + if (!slots)
7.175 + return NULL;
7.176 +
7.177 + // Build the descriptor table, mapping each slot to an offset and type.
7.178 + Local<Type> type(zone);
7.179 + for (unsigned i = 0; i < nvars; i++) {
7.180 + assert(vars[i]->slot() == i);
7.181 + type = vars[i]->type();
7.182 +
7.183 + EnvironmentSlotDescriptor &desc = slots->slots()[i];
7.184 + if (!structure.add(type, &desc.offset))
7.185 + return NULL;
7.186 +
7.187 + desc.type = type;
7.188 + }
7.189 +
7.190 + // Allocate the actual map now.
7.191 + size_t bytesNeeded = sizeof(EnvironmentMap) + structure.traceableOffsetCount() * sizeof(unsigned);
7.192 +
7.193 + Local<EnvironmentMap> map(zone);
7.194 + map = EnvironmentMap::cast(zone->allocateMap(MapKind_Environment, bytesNeeded, MapKind_MetaEnvironment));
7.195 + if (!map)
7.196 + return NULL;
7.197 +
7.198 + // Fill in the map fields, and copy the traceable offsets structure.
7.199 + map->structureSize_ = structure.structureSize();
7.200 + map->traceOffsetCount_ = structure.traceableOffsetCount();
7.201 + map->slots_ = slots;
7.202 + memcpy(const_cast<unsigned *>(map->traceOffsets()), structure.offsets(), sizeof(unsigned) * structure.traceableOffsetCount());
7.203 +
7.204 + return map;
7.205 +}
7.206 #endif
7.207 \ No newline at end of file
8.1 --- a/src/Environments.h Mon Jun 10 00:46:29 2013 +0100
8.2 +++ b/src/Environments.h Mon Jun 10 01:04:43 2013 +0100
8.3 @@ -1,169 +1,169 @@
8.4 -/*
8.5 - * Copyright (C) 2012 David Anderson
8.6 - *
8.7 - * This file is part of JITCraft.
8.8 - *
8.9 - * JITCraft is free software: you can redistribute it and/or modify it under
8.10 - * the terms of the GNU General Public License as published by the Free
8.11 - * Software Foundation, either version 3 of the License, or (at your option)
8.12 - * any later version.
8.13 - *
8.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
8.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8.17 - *
8.18 - * You should have received a copy of the GNU General Public License along with
8.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
8.20 - */
8.21 -#ifndef _include_ke_environment_h_
8.22 -#define _include_ke_environment_h_
8.23 -
8.24 -#include "Objects.h"
8.25 -#include "Handles.h"
8.26 -#include "Heap.h"
8.27 -#include "FixedArray.h"
8.28 -
8.29 -namespace ke {
8.30 -
8.31 -class EnvironmentMap;
8.32 -class Variable;
8.33 -class ByteArray;
8.34 -class Type;
8.35 -
8.36 -// An environment represents the lexical environment of a code or function
8.37 -// object. It used for variables which may be accessed outside a function's
8.38 -// normal activation (i.e., upvars).
8.39 -//
8.40 -// A module uses an Environment to store its global variables.
8.41 -class Environment : public Object
8.42 -{
8.43 - template <typename T>
8.44 - inline T *pointerToSlot(unsigned slot);
8.45 -
8.46 - public:
8.47 - static Environment *New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
8.48 -
8.49 - inline EnvironmentMap *map();
8.50 - inline size_t objSize();
8.51 -
8.52 - float getFloat(unsigned slot) {
8.53 - return *pointerToSlot<float>(slot);
8.54 - }
8.55 - int getInt32(unsigned slot) {
8.56 - return *pointerToSlot<int>(slot);
8.57 - }
8.58 - Object *getObject(unsigned slot) {
8.59 - return *pointerToSlot<Object *>(slot);
8.60 - }
8.61 - void setFloat(unsigned slot, float f) {
8.62 - *pointerToSlot<float>(slot) = f;
8.63 - }
8.64 - void setInt32(unsigned slot, int i) {
8.65 - *pointerToSlot<int>(slot) = i;
8.66 - }
8.67 - void setObject(unsigned slot, Object *obj) {
8.68 - // :TODO: write barrier
8.69 - *pointerToSlot<Object *>(slot) = obj;
8.70 - }
8.71 -
8.72 - static inline size_t offsetOfSlotOffset(unsigned offset) {
8.73 - return sizeof(Environment) + offset;
8.74 - }
8.75 -
8.76 - static inline Environment *cast(Object *obj) {
8.77 - assert(!obj || obj->is(MapKind_Environment));
8.78 - return reinterpret_cast<Environment *>(obj);
8.79 - }
8.80 -};
8.81 -
8.82 -struct EnvironmentSlotDescriptor
8.83 -{
8.84 - Barriered<Type> type;
8.85 - unsigned offset;
8.86 -};
8.87 -
8.88 -class EnvironmentSlotDescriptorArray : public Object
8.89 -{
8.90 - unsigned length_;
8.91 -
8.92 - public:
8.93 - static EnvironmentSlotDescriptorArray *New(Zone *zone, unsigned length);
8.94 -
8.95 - EnvironmentSlotDescriptor *slots() {
8.96 - return reinterpret_cast<EnvironmentSlotDescriptor *>(this + 1);
8.97 - }
8.98 - EnvironmentSlotDescriptor &at(unsigned slot) {
8.99 - assert(slot < length_);
8.100 - return slots()[slot];
8.101 - }
8.102 - unsigned length() {
8.103 - return length_;
8.104 - }
8.105 - unsigned objSize() {
8.106 - return sizeof(*this) + length() * sizeof(EnvironmentSlotDescriptorArray);
8.107 - }
8.108 -
8.109 - static inline EnvironmentSlotDescriptorArray *cast(Object *obj) {
8.110 - assert(!obj || obj->is(MapKind_EnvironmentSlotDescriptorArray));
8.111 - return reinterpret_cast<EnvironmentSlotDescriptorArray *>(obj);
8.112 - }
8.113 -};
8.114 -
8.115 -class EnvironmentMap : public Map
8.116 -{
8.117 - unsigned structureSize_;
8.118 - unsigned traceOffsetCount_;
8.119 - Barriered<EnvironmentSlotDescriptorArray> slots_;
8.120 -
8.121 - public:
8.122 - static EnvironmentMap *New(Zone *zone, unsigned nvars, Variable **vars);
8.123 -
8.124 - unsigned structureSize() {
8.125 - return structureSize_;
8.126 - }
8.127 - unsigned traceOffsetCount() {
8.128 - return traceOffsetCount_;
8.129 - }
8.130 - const unsigned *traceOffsets() {
8.131 - return reinterpret_cast<unsigned *>(this + 1);
8.132 - }
8.133 - size_t objSize() {
8.134 - return sizeof(EnvironmentMap) + sizeof(unsigned) * traceOffsetCount();
8.135 - }
8.136 - EnvironmentSlotDescriptor &slotDescriptor(unsigned slot) {
8.137 - return slots_->at(slot);
8.138 - }
8.139 -
8.140 - // Begin GC descriptors.
8.141 - static inline size_t offsetOfSlots() {
8.142 - return OFFSETOF(EnvironmentMap, slots_);
8.143 - }
8.144 - // End GC descriptors.
8.145 -
8.146 - static inline EnvironmentMap *cast(Object *obj) {
8.147 - assert(!obj || obj->is(MapKind_MetaEnvironment));
8.148 - return reinterpret_cast<EnvironmentMap *>(obj);
8.149 - }
8.150 -};
8.151 -
8.152 -size_t
8.153 -Environment::objSize()
8.154 -{
8.155 - return sizeof(Environment) + map()->structureSize();
8.156 -}
8.157 -
8.158 -EnvironmentMap *
8.159 -Environment::map()
8.160 -{
8.161 - return EnvironmentMap::cast(Object::map());
8.162 -}
8.163 -
8.164 -template <typename T> T *
8.165 -Environment::pointerToSlot(unsigned slot)
8.166 -{
8.167 - return reinterpret_cast<T *>(reinterpret_cast<char *>(this + 1) + map()->slotDescriptor(slot).offset);
8.168 -}
8.169 -
8.170 -}
8.171 -
8.172 -#endif // _include_ke_environment_h_
8.173 +/*
8.174 + * Copyright (C) 2012 David Anderson
8.175 + *
8.176 + * This file is part of JITCraft.
8.177 + *
8.178 + * JITCraft is free software: you can redistribute it and/or modify it under
8.179 + * the terms of the GNU General Public License as published by the Free
8.180 + * Software Foundation, either version 3 of the License, or (at your option)
8.181 + * any later version.
8.182 + *
8.183 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
8.184 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8.185 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
8.186 + *
8.187 + * You should have received a copy of the GNU General Public License along with
8.188 + * JITCraft. If not, see http://www.gnu.org/licenses/.
8.189 + */
8.190 +#ifndef _include_ke_environment_h_
8.191 +#define _include_ke_environment_h_
8.192 +
8.193 +#include "Objects.h"
8.194 +#include "Handles.h"
8.195 +#include "Heap.h"
8.196 +#include "FixedArray.h"
8.197 +
8.198 +namespace ke {
8.199 +
8.200 +class EnvironmentMap;
8.201 +class Variable;
8.202 +class ByteArray;
8.203 +class Type;
8.204 +
8.205 +// An environment represents the lexical environment of a code or function
8.206 +// object. It used for variables which may be accessed outside a function's
8.207 +// normal activation (i.e., upvars).
8.208 +//
8.209 +// A module uses an Environment to store its global variables.
8.210 +class Environment : public Object
8.211 +{
8.212 + template <typename T>
8.213 + inline T *pointerToSlot(unsigned slot);
8.214 +
8.215 + public:
8.216 + static Environment *New(Zone *zone, Handle<EnvironmentMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
8.217 +
8.218 + inline EnvironmentMap *map();
8.219 + inline size_t objSize();
8.220 +
8.221 + float getFloat(unsigned slot) {
8.222 + return *pointerToSlot<float>(slot);
8.223 + }
8.224 + int getInt32(unsigned slot) {
8.225 + return *pointerToSlot<int>(slot);
8.226 + }
8.227 + Object *getObject(unsigned slot) {
8.228 + return *pointerToSlot<Object *>(slot);
8.229 + }
8.230 + void setFloat(unsigned slot, float f) {
8.231 + *pointerToSlot<float>(slot) = f;
8.232 + }
8.233 + void setInt32(unsigned slot, int i) {
8.234 + *pointerToSlot<int>(slot) = i;
8.235 + }
8.236 + void setObject(unsigned slot, Object *obj) {
8.237 + // :TODO: write barrier
8.238 + *pointerToSlot<Object *>(slot) = obj;
8.239 + }
8.240 +
8.241 + static inline size_t offsetOfSlotOffset(unsigned offset) {
8.242 + return sizeof(Environment) + offset;
8.243 + }
8.244 +
8.245 + static inline Environment *cast(Object *obj) {
8.246 + assert(!obj || obj->is(MapKind_Environment));
8.247 + return reinterpret_cast<Environment *>(obj);
8.248 + }
8.249 +};
8.250 +
8.251 +struct EnvironmentSlotDescriptor
8.252 +{
8.253 + Barriered<Type> type;
8.254 + unsigned offset;
8.255 +};
8.256 +
8.257 +class EnvironmentSlotDescriptorArray : public Object
8.258 +{
8.259 + unsigned length_;
8.260 +
8.261 + public:
8.262 + static EnvironmentSlotDescriptorArray *New(Zone *zone, unsigned length);
8.263 +
8.264 + EnvironmentSlotDescriptor *slots() {
8.265 + return reinterpret_cast<EnvironmentSlotDescriptor *>(this + 1);
8.266 + }
8.267 + EnvironmentSlotDescriptor &at(unsigned slot) {
8.268 + assert(slot < length_);
8.269 + return slots()[slot];
8.270 + }
8.271 + unsigned length() {
8.272 + return length_;
8.273 + }
8.274 + unsigned objSize() {
8.275 + return sizeof(*this) + length() * sizeof(EnvironmentSlotDescriptorArray);
8.276 + }
8.277 +
8.278 + static inline EnvironmentSlotDescriptorArray *cast(Object *obj) {
8.279 + assert(!obj || obj->is(MapKind_EnvironmentSlotDescriptorArray));
8.280 + return reinterpret_cast<EnvironmentSlotDescriptorArray *>(obj);
8.281 + }
8.282 +};
8.283 +
8.284 +class EnvironmentMap : public Map
8.285 +{
8.286 + unsigned structureSize_;
8.287 + unsigned traceOffsetCount_;
8.288 + Barriered<EnvironmentSlotDescriptorArray> slots_;
8.289 +
8.290 + public:
8.291 + static EnvironmentMap *New(Zone *zone, unsigned nvars, Variable **vars);
8.292 +
8.293 + unsigned structureSize() {
8.294 + return structureSize_;
8.295 + }
8.296 + unsigned traceOffsetCount() {
8.297 + return traceOffsetCount_;
8.298 + }
8.299 + const unsigned *traceOffsets() {
8.300 + return reinterpret_cast<unsigned *>(this + 1);
8.301 + }
8.302 + size_t objSize() {
8.303 + return sizeof(EnvironmentMap) + sizeof(unsigned) * traceOffsetCount();
8.304 + }
8.305 + EnvironmentSlotDescriptor &slotDescriptor(unsigned slot) {
8.306 + return slots_->at(slot);
8.307 + }
8.308 +
8.309 + // Begin GC descriptors.
8.310 + static inline size_t offsetOfSlots() {
8.311 + return OFFSETOF(EnvironmentMap, slots_);
8.312 + }
8.313 + // End GC descriptors.
8.314 +
8.315 + static inline EnvironmentMap *cast(Object *obj) {
8.316 + assert(!obj || obj->is(MapKind_MetaEnvironment));
8.317 + return reinterpret_cast<EnvironmentMap *>(obj);
8.318 + }
8.319 +};
8.320 +
8.321 +size_t
8.322 +Environment::objSize()
8.323 +{
8.324 + return sizeof(Environment) + map()->structureSize();
8.325 +}
8.326 +
8.327 +EnvironmentMap *
8.328 +Environment::map()
8.329 +{
8.330 + return EnvironmentMap::cast(Object::map());
8.331 +}
8.332 +
8.333 +template <typename T> T *
8.334 +Environment::pointerToSlot(unsigned slot)
8.335 +{
8.336 + return reinterpret_cast<T *>(reinterpret_cast<char *>(this + 1) + map()->slotDescriptor(slot).offset);
8.337 +}
8.338 +
8.339 +}
8.340 +
8.341 +#endif // _include_ke_environment_h_
9.1 --- a/src/Exception.cpp Mon Jun 10 00:46:29 2013 +0100
9.2 +++ b/src/Exception.cpp Mon Jun 10 01:04:43 2013 +0100
9.3 @@ -1,31 +1,31 @@
9.4 -/* vim: set ts=4 sw=4 tw=99 et:
9.5 - *
9.6 - * Copyright (C) 2012 David Anderson
9.7 - *
9.8 - * This file is part of SourcePawn.
9.9 - *
9.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
9.11 - * the terms of the GNU General Public License as published by the Free
9.12 - * Software Foundation, either version 3 of the License, or (at your option)
9.13 - * any later version.
9.14 - *
9.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
9.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
9.18 - *
9.19 - * You should have received a copy of the GNU General Public License along with
9.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
9.21 - */
9.22 -#include "Utility.h"
9.23 -#include "Messages.h"
9.24 -
9.25 -using namespace ke;
9.26 -
9.27 -const MessageInfo ke::Messages[] =
9.28 -{
9.29 -#define MSG(Name, Type, String) \
9.30 - { MessageType_##Type, String },
9.31 -# include "Messages.tbl"
9.32 -#undef MSG
9.33 - { MessageType_SyntaxError, NULL }
9.34 -};
9.35 +/* vim: set ts=4 sw=4 tw=99 et:
9.36 + *
9.37 + * Copyright (C) 2012 David Anderson
9.38 + *
9.39 + * This file is part of SourcePawn.
9.40 + *
9.41 + * SourcePawn is free software: you can redistribute it and/or modify it under
9.42 + * the terms of the GNU General Public License as published by the Free
9.43 + * Software Foundation, either version 3 of the License, or (at your option)
9.44 + * any later version.
9.45 + *
9.46 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
9.47 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9.48 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
9.49 + *
9.50 + * You should have received a copy of the GNU General Public License along with
9.51 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
9.52 + */
9.53 +#include "Utility.h"
9.54 +#include "Messages.h"
9.55 +
9.56 +using namespace ke;
9.57 +
9.58 +const MessageInfo ke::Messages[] =
9.59 +{
9.60 +#define MSG(Name, Type, String) \
9.61 + { MessageType_##Type, String },
9.62 +# include "Messages.tbl"
9.63 +#undef MSG
9.64 + { MessageType_SyntaxError, NULL }
9.65 +};
10.1 --- a/src/FixedArray.cpp Mon Jun 10 00:46:29 2013 +0100
10.2 +++ b/src/FixedArray.cpp Mon Jun 10 01:04:43 2013 +0100
10.3 @@ -1,78 +1,78 @@
10.4 -/*
10.5 - * Copyright (C) 2012 David Anderson
10.6 - *
10.7 - * This file is part of SourcePawn.
10.8 - *
10.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
10.10 - * the terms of the GNU General Public License as published by the Free
10.11 - * Software Foundation, either version 3 of the License, or (at your option)
10.12 - * any later version.
10.13 - *
10.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
10.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10.17 - *
10.18 - * You should have received a copy of the GNU General Public License along with
10.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
10.20 - */
10.21 -#include <limits.h>
10.22 -#include <string.h>
10.23 -#include "FixedArray.h"
10.24 -#include "Zone.h"
10.25 -#include "Heap-inl.h"
10.26 -
10.27 -using namespace ke;
10.28 -
10.29 -static const unsigned kMaxFixedArrayLength = ((INT_MAX - sizeof(FixedArray)) / sizeof(ke::Object *));
10.30 -
10.31 -FixedArray *
10.32 -FixedArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
10.33 -{
10.34 - if (length >= kMaxFixedArrayLength) {
10.35 - zone->reportError(Message_ArrayTooBig);
10.36 - return NULL;
10.37 - }
10.38 -
10.39 - Local<FixedArray> array(zone, FixedArray::cast(zone->allocate(MapKind_FixedArray, SizeFor(length), tenure)));
10.40 - if (!array)
10.41 - return NULL;
10.42 -
10.43 - array->length_ = length;
10.44 - memset(array->vec(), 0, length * sizeof(Object *));
10.45 - return array;
10.46 -}
10.47 -
10.48 -ByteArray *
10.49 -ByteArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
10.50 -{
10.51 - if (length >= kMaxFixedArrayLength) {
10.52 - zone->reportError(Message_ArrayTooBig);
10.53 - return NULL;
10.54 - }
10.55 -
10.56 - Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(MapKind_ByteArray, SizeFor(length), tenure)));
10.57 - if (!array)
10.58 - return NULL;
10.59 -
10.60 - array->length_ = length;
10.61 - memset(array->raw(), 0, length);
10.62 - return array;
10.63 -}
10.64 -
10.65 -ByteArray *
10.66 -ByteArray::New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure)
10.67 -{
10.68 - if (length >= kMaxFixedArrayLength) {
10.69 - zone->reportError(Message_ArrayTooBig);
10.70 - return NULL;
10.71 - }
10.72 -
10.73 - Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(map, SizeFor(length), tenure)));
10.74 - if (!array)
10.75 - return NULL;
10.76 -
10.77 - array->length_ = length;
10.78 - memset(array->raw(), 0, length);
10.79 - return array;
10.80 -}
10.81 -
10.82 +/*
10.83 + * Copyright (C) 2012 David Anderson
10.84 + *
10.85 + * This file is part of SourcePawn.
10.86 + *
10.87 + * SourcePawn is free software: you can redistribute it and/or modify it under
10.88 + * the terms of the GNU General Public License as published by the Free
10.89 + * Software Foundation, either version 3 of the License, or (at your option)
10.90 + * any later version.
10.91 + *
10.92 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
10.93 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10.94 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10.95 + *
10.96 + * You should have received a copy of the GNU General Public License along with
10.97 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
10.98 + */
10.99 +#include <limits.h>
10.100 +#include <string.h>
10.101 +#include "FixedArray.h"
10.102 +#include "Zone.h"
10.103 +#include "Heap-inl.h"
10.104 +
10.105 +using namespace ke;
10.106 +
10.107 +static const unsigned kMaxFixedArrayLength = ((INT_MAX - sizeof(FixedArray)) / sizeof(ke::Object *));
10.108 +
10.109 +FixedArray *
10.110 +FixedArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
10.111 +{
10.112 + if (length >= kMaxFixedArrayLength) {
10.113 + zone->reportError(Message_ArrayTooBig);
10.114 + return NULL;
10.115 + }
10.116 +
10.117 + Local<FixedArray> array(zone, FixedArray::cast(zone->allocate(MapKind_FixedArray, SizeFor(length), tenure)));
10.118 + if (!array)
10.119 + return NULL;
10.120 +
10.121 + array->length_ = length;
10.122 + memset(array->vec(), 0, length * sizeof(Object *));
10.123 + return array;
10.124 +}
10.125 +
10.126 +ByteArray *
10.127 +ByteArray::New(Zone *zone, unsigned length, Heap::Tenure tenure)
10.128 +{
10.129 + if (length >= kMaxFixedArrayLength) {
10.130 + zone->reportError(Message_ArrayTooBig);
10.131 + return NULL;
10.132 + }
10.133 +
10.134 + Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(MapKind_ByteArray, SizeFor(length), tenure)));
10.135 + if (!array)
10.136 + return NULL;
10.137 +
10.138 + array->length_ = length;
10.139 + memset(array->raw(), 0, length);
10.140 + return array;
10.141 +}
10.142 +
10.143 +ByteArray *
10.144 +ByteArray::New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure)
10.145 +{
10.146 + if (length >= kMaxFixedArrayLength) {
10.147 + zone->reportError(Message_ArrayTooBig);
10.148 + return NULL;
10.149 + }
10.150 +
10.151 + Local<ByteArray> array(zone, ByteArray::cast(zone->allocate(map, SizeFor(length), tenure)));
10.152 + if (!array)
10.153 + return NULL;
10.154 +
10.155 + array->length_ = length;
10.156 + memset(array->raw(), 0, length);
10.157 + return array;
10.158 +}
10.159 +
11.1 --- a/src/FixedArray.h Mon Jun 10 00:46:29 2013 +0100
11.2 +++ b/src/FixedArray.h Mon Jun 10 01:04:43 2013 +0100
11.3 @@ -1,99 +1,99 @@
11.4 -/* vim: set ts=4 sw=4 tw=99 et:
11.5 - *
11.6 - * Copyright (C) 2012 David Anderson
11.7 - *
11.8 - * This file is part of SourcePawn.
11.9 - *
11.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
11.11 - * the terms of the GNU General Public License as published by the Free
11.12 - * Software Foundation, either version 3 of the License, or (at your option)
11.13 - * any later version.
11.14 - *
11.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
11.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11.18 - *
11.19 - * You should have received a copy of the GNU General Public License along with
11.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
11.21 - */
11.22 -#ifndef _include_jitcraft_fixedarray_h_
11.23 -#define _include_jitcraft_fixedarray_h_
11.24 -
11.25 -#include "Heap.h"
11.26 -
11.27 -namespace ke {
11.28 -
11.29 -// A fixed-length array that contains Object * slots.
11.30 -class FixedArray : public Object
11.31 -{
11.32 - uint32 length_;
11.33 -
11.34 - private:
11.35 - Object **vec() {
11.36 - return reinterpret_cast<Object **>(this + 1);
11.37 - }
11.38 -
11.39 - public:
11.40 - static FixedArray *New(Zone *zone, unsigned length, Heap::Tenure tenure);
11.41 -
11.42 - unsigned length() {
11.43 - return length_;
11.44 - }
11.45 - Object *at(size_t i) {
11.46 - assert(i < length());
11.47 - return vec()[i];
11.48 - }
11.49 - void set(Zone *zone, size_t i, Object *obj) {
11.50 - assert(i < length());
11.51 - write(zone, &vec()[i], obj);
11.52 - }
11.53 - size_t objSize() {
11.54 - return SizeFor(length());
11.55 - }
11.56 -
11.57 - static inline size_t SizeFor(unsigned length) {
11.58 - return sizeof(FixedArray) + sizeof(Object *) * length;
11.59 - }
11.60 -
11.61 - static inline FixedArray *cast(Object *obj) {
11.62 - assert(!obj || obj->is(MapKind_FixedArray));
11.63 - return reinterpret_cast<FixedArray *>(obj);
11.64 - }
11.65 -};
11.66 -
11.67 -// A fixed-length array containing raw bytes.
11.68 -class ByteArray : public Object
11.69 -{
11.70 - uint32 length_;
11.71 -
11.72 - public:
11.73 - static ByteArray *New(Zone *zone, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
11.74 - static ByteArray *New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
11.75 -
11.76 - unsigned length() {
11.77 - return length_;
11.78 - }
11.79 - Address raw() {
11.80 - return Address(this) + offsetToElements();
11.81 - }
11.82 - size_t objSize() {
11.83 - return SizeFor(length());
11.84 - }
11.85 -
11.86 - static inline size_t offsetToElements() {
11.87 - return sizeof(ByteArray);
11.88 - }
11.89 -
11.90 - static inline size_t SizeFor(unsigned length) {
11.91 - return sizeof(ByteArray) + sizeof(uint8) * length;
11.92 - }
11.93 -
11.94 - static inline ByteArray *cast(Object *obj) {
11.95 - assert(!obj || obj->is(MapKind_ByteArray));
11.96 - return reinterpret_cast<ByteArray *>(obj);
11.97 - }
11.98 -};
11.99 -
11.100 -}
11.101 -
11.102 -#endif // _include_jitcraft_fixedarray_h_
11.103 +/* vim: set ts=4 sw=4 tw=99 et:
11.104 + *
11.105 + * Copyright (C) 2012 David Anderson
11.106 + *
11.107 + * This file is part of SourcePawn.
11.108 + *
11.109 + * SourcePawn is free software: you can redistribute it and/or modify it under
11.110 + * the terms of the GNU General Public License as published by the Free
11.111 + * Software Foundation, either version 3 of the License, or (at your option)
11.112 + * any later version.
11.113 + *
11.114 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
11.115 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11.116 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11.117 + *
11.118 + * You should have received a copy of the GNU General Public License along with
11.119 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
11.120 + */
11.121 +#ifndef _include_jitcraft_fixedarray_h_
11.122 +#define _include_jitcraft_fixedarray_h_
11.123 +
11.124 +#include "Heap.h"
11.125 +
11.126 +namespace ke {
11.127 +
11.128 +// A fixed-length array that contains Object * slots.
11.129 +class FixedArray : public Object
11.130 +{
11.131 + uint32 length_;
11.132 +
11.133 + private:
11.134 + Object **vec() {
11.135 + return reinterpret_cast<Object **>(this + 1);
11.136 + }
11.137 +
11.138 + public:
11.139 + static FixedArray *New(Zone *zone, unsigned length, Heap::Tenure tenure);
11.140 +
11.141 + unsigned length() {
11.142 + return length_;
11.143 + }
11.144 + Object *at(size_t i) {
11.145 + assert(i < length());
11.146 + return vec()[i];
11.147 + }
11.148 + void set(Zone *zone, size_t i, Object *obj) {
11.149 + assert(i < length());
11.150 + write(zone, &vec()[i], obj);
11.151 + }
11.152 + size_t objSize() {
11.153 + return SizeFor(length());
11.154 + }
11.155 +
11.156 + static inline size_t SizeFor(unsigned length) {
11.157 + return sizeof(FixedArray) + sizeof(Object *) * length;
11.158 + }
11.159 +
11.160 + static inline FixedArray *cast(Object *obj) {
11.161 + assert(!obj || obj->is(MapKind_FixedArray));
11.162 + return reinterpret_cast<FixedArray *>(obj);
11.163 + }
11.164 +};
11.165 +
11.166 +// A fixed-length array containing raw bytes.
11.167 +class ByteArray : public Object
11.168 +{
11.169 + uint32 length_;
11.170 +
11.171 + public:
11.172 + static ByteArray *New(Zone *zone, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
11.173 + static ByteArray *New(Zone *zone, Handle<Map> map, unsigned length, Heap::Tenure tenure = Heap::Tenure_Default);
11.174 +
11.175 + unsigned length() {
11.176 + return length_;
11.177 + }
11.178 + Address raw() {
11.179 + return Address(this) + offsetToElements();
11.180 + }
11.181 + size_t objSize() {
11.182 + return SizeFor(length());
11.183 + }
11.184 +
11.185 + static inline size_t offsetToElements() {
11.186 + return sizeof(ByteArray);
11.187 + }
11.188 +
11.189 + static inline size_t SizeFor(unsigned length) {
11.190 + return sizeof(ByteArray) + sizeof(uint8) * length;
11.191 + }
11.192 +
11.193 + static inline ByteArray *cast(Object *obj) {
11.194 + assert(!obj || obj->is(MapKind_ByteArray));
11.195 + return reinterpret_cast<ByteArray *>(obj);
11.196 + }
11.197 +};
11.198 +
11.199 +}
11.200 +
11.201 +#endif // _include_jitcraft_fixedarray_h_
12.1 --- a/src/Functions.cpp Mon Jun 10 00:46:29 2013 +0100
12.2 +++ b/src/Functions.cpp Mon Jun 10 01:04:43 2013 +0100
12.3 @@ -1,50 +1,50 @@
12.4 -/*
12.5 - * Copyright (C) 2012 David Anderson
12.6 - *
12.7 - * This file is part of SourcePawn.
12.8 - *
12.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
12.10 - * the terms of the GNU General Public License as published by the Free
12.11 - * Software Foundation, either version 3 of the License, or (at your option)
12.12 - * any later version.
12.13 - *
12.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
12.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12.17 - *
12.18 - * You should have received a copy of the GNU General Public License along with
12.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
12.20 - */
12.21 -#include "Functions.h"
12.22 -#include "Modules.h"
12.23 -#include "Zone.h"
12.24 -#include "Heap-inl.h"
12.25 -
12.26 -using namespace ke;
12.27 -
12.28 -Function *
12.29 -Function::New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
12.30 - const SourcePosition &pos)
12.31 -{
12.32 - Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
12.33 - if (!fun)
12.34 - return NULL;
12.35 -
12.36 - fun->code_ = code;
12.37 - fun->pos_ = pos;
12.38 - fun->type_ = type;
12.39 - fun->name_ = name;
12.40 - return fun;
12.41 -}
12.42 -
12.43 -Native *
12.44 -Native::New(Zone *zone, Handle<FunctionType> type, size_t index)
12.45 -{
12.46 - Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
12.47 - if (!fun)
12.48 - return NULL;
12.49 -
12.50 - fun->type_ = type;
12.51 - fun->index_ = index;
12.52 - return fun;
12.53 -}
12.54 +/*
12.55 + * Copyright (C) 2012 David Anderson
12.56 + *
12.57 + * This file is part of SourcePawn.
12.58 + *
12.59 + * SourcePawn is free software: you can redistribute it and/or modify it under
12.60 + * the terms of the GNU General Public License as published by the Free
12.61 + * Software Foundation, either version 3 of the License, or (at your option)
12.62 + * any later version.
12.63 + *
12.64 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
12.65 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12.66 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12.67 + *
12.68 + * You should have received a copy of the GNU General Public License along with
12.69 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
12.70 + */
12.71 +#include "Functions.h"
12.72 +#include "Modules.h"
12.73 +#include "Zone.h"
12.74 +#include "Heap-inl.h"
12.75 +
12.76 +using namespace ke;
12.77 +
12.78 +Function *
12.79 +Function::New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
12.80 + const SourcePosition &pos)
12.81 +{
12.82 + Function *fun = Function::cast(zone->allocate(MapKind_Function, sizeof(Function), Heap::Tenure_Old));
12.83 + if (!fun)
12.84 + return NULL;
12.85 +
12.86 + fun->code_ = code;
12.87 + fun->pos_ = pos;
12.88 + fun->type_ = type;
12.89 + fun->name_ = name;
12.90 + return fun;
12.91 +}
12.92 +
12.93 +Native *
12.94 +Native::New(Zone *zone, Handle<FunctionType> type, size_t index)
12.95 +{
12.96 + Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
12.97 + if (!fun)
12.98 + return NULL;
12.99 +
12.100 + fun->type_ = type;
12.101 + fun->index_ = index;
12.102 + return fun;
12.103 +}
13.1 --- a/src/Functions.h Mon Jun 10 00:46:29 2013 +0100
13.2 +++ b/src/Functions.h Mon Jun 10 01:04:43 2013 +0100
13.3 @@ -1,113 +1,113 @@
13.4 -/*
13.5 - * Copyright (C) 2012 David Anderson
13.6 - *
13.7 - * This file is part of SourcePawn.
13.8 - *
13.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
13.10 - * the terms of the GNU General Public License as published by the Free
13.11 - * Software Foundation, either version 3 of the License, or (at your option)
13.12 - * any later version.
13.13 - *
13.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
13.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13.17 - *
13.18 - * You should have received a copy of the GNU General Public License along with
13.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
13.20 - */
13.21 -#ifndef _include_jitcraft_function_h_
13.22 -#define _include_jitcraft_function_h_
13.23 -
13.24 -#include "Heap.h"
13.25 -#include "Barriers.h"
13.26 -#include "Types.h"
13.27 -#include "Opcodes.h"
13.28 -
13.29 -namespace ke {
13.30 -
13.31 -class Code;
13.32 -class Module;
13.33 -class String;
13.34 -
13.35 -class Function : public Object
13.36 -{
13.37 - Barriered<Code> code_;
13.38 - Barriered<FunctionType> type_;
13.39 - Barriered<String> name_;
13.40 - SourcePosition pos_;
13.41 -
13.42 - public:
13.43 - static Function *New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
13.44 - const SourcePosition &pos);
13.45 -
13.46 - Code *code() const {
13.47 - return code_;
13.48 - }
13.49 - FunctionType *type() const {
13.50 - return type_;
13.51 - }
13.52 - String *name() const {
13.53 - return name_;
13.54 - }
13.55 - const SourcePosition &pos() {
13.56 - return pos_;
13.57 - }
13.58 - unsigned nargs() {
13.59 - return type()->parameters()->length();
13.60 - }
13.61 - Type *argType(size_t index) {
13.62 - return type()->parameterAt(index);
13.63 - }
13.64 -
13.65 - // Begin GC Descriptor.
13.66 - static inline size_t offsetOfCode() {
13.67 - return OFFSETOF(Function, code_);
13.68 - }
13.69 - static inline size_t offsetOfType() {
13.70 - return OFFSETOF(Function, type_);
13.71 - }
13.72 - static inline size_t offsetOfName() {
13.73 - return OFFSETOF(Function, name_);
13.74 - }
13.75 - // End GC Descriptor.
13.76 -
13.77 - static inline Function *cast(Object *obj) {
13.78 - assert(!obj || obj->is(MapKind_Function));
13.79 - return reinterpret_cast<Function *>(obj);
13.80 - }
13.81 -};
13.82 -
13.83 -// A Native is a function with a very specialized calling convention, intended
13.84 -// for earlier ISourcePawnEngine API compatibility.
13.85 -class Native : public Object
13.86 -{
13.87 - Barriered<FunctionType> type_;
13.88 -
13.89 - // Index into the Zone's native table.
13.90 - size_t index_;
13.91 -
13.92 - public:
13.93 - static Native *New(Zone *zone, Handle<FunctionType> type, size_t index);
13.94 -
13.95 - FunctionType *type() {
13.96 - return type_;
13.97 - }
13.98 - size_t index() const {
13.99 - return index_;
13.100 - }
13.101 -
13.102 - // Begin GC Descriptor.
13.103 - static inline size_t offsetOfType() {
13.104 - return OFFSETOF(Native, type_);
13.105 - }
13.106 - // End GC Descriptor.
13.107 -
13.108 - static inline Native *cast(Object *obj) {
13.109 - assert(!obj || obj->is(MapKind_Native));
13.110 - return reinterpret_cast<Native *>(obj);
13.111 - }
13.112 -};
13.113 -
13.114 -}
13.115 -
13.116 -#endif // _include_jitcraft_function_h_
13.117 +/*
13.118 + * Copyright (C) 2012 David Anderson
13.119 + *
13.120 + * This file is part of SourcePawn.
13.121 + *
13.122 + * SourcePawn is free software: you can redistribute it and/or modify it under
13.123 + * the terms of the GNU General Public License as published by the Free
13.124 + * Software Foundation, either version 3 of the License, or (at your option)
13.125 + * any later version.
13.126 + *
13.127 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
13.128 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13.129 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13.130 + *
13.131 + * You should have received a copy of the GNU General Public License along with
13.132 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
13.133 + */
13.134 +#ifndef _include_jitcraft_function_h_
13.135 +#define _include_jitcraft_function_h_
13.136 +
13.137 +#include "Heap.h"
13.138 +#include "Barriers.h"
13.139 +#include "Types.h"
13.140 +#include "Opcodes.h"
13.141 +
13.142 +namespace ke {
13.143 +
13.144 +class Code;
13.145 +class Module;
13.146 +class String;
13.147 +
13.148 +class Function : public Object
13.149 +{
13.150 + Barriered<Code> code_;
13.151 + Barriered<FunctionType> type_;
13.152 + Barriered<String> name_;
13.153 + SourcePosition pos_;
13.154 +
13.155 + public:
13.156 + static Function *New(Zone *zone, Handle<Code> code, Handle<FunctionType> type, Handle<String> name,
13.157 + const SourcePosition &pos);
13.158 +
13.159 + Code *code() const {
13.160 + return code_;
13.161 + }
13.162 + FunctionType *type() const {
13.163 + return type_;
13.164 + }
13.165 + String *name() const {
13.166 + return name_;
13.167 + }
13.168 + const SourcePosition &pos() {
13.169 + return pos_;
13.170 + }
13.171 + unsigned nargs() {
13.172 + return type()->parameters()->length();
13.173 + }
13.174 + Type *argType(size_t index) {
13.175 + return type()->parameterAt(index);
13.176 + }
13.177 +
13.178 + // Begin GC Descriptor.
13.179 + static inline size_t offsetOfCode() {
13.180 + return OFFSETOF(Function, code_);
13.181 + }
13.182 + static inline size_t offsetOfType() {
13.183 + return OFFSETOF(Function, type_);
13.184 + }
13.185 + static inline size_t offsetOfName() {
13.186 + return OFFSETOF(Function, name_);
13.187 + }
13.188 + // End GC Descriptor.
13.189 +
13.190 + static inline Function *cast(Object *obj) {
13.191 + assert(!obj || obj->is(MapKind_Function));
13.192 + return reinterpret_cast<Function *>(obj);
13.193 + }
13.194 +};
13.195 +
13.196 +// A Native is a function with a very specialized calling convention, intended
13.197 +// for earlier ISourcePawnEngine API compatibility.
13.198 +class Native : public Object
13.199 +{
13.200 + Barriered<FunctionType> type_;
13.201 +
13.202 + // Index into the Zone's native table.
13.203 + size_t index_;
13.204 +
13.205 + public:
13.206 + static Native *New(Zone *zone, Handle<FunctionType> type, size_t index);
13.207 +
13.208 + FunctionType *type() {
13.209 + return type_;
13.210 + }
13.211 + size_t index() const {
13.212 + return index_;
13.213 + }
13.214 +
13.215 + // Begin GC Descriptor.
13.216 + static inline size_t offsetOfType() {
13.217 + return OFFSETOF(Native, type_);
13.218 + }
13.219 + // End GC Descriptor.
13.220 +
13.221 + static inline Native *cast(Object *obj) {
13.222 + assert(!obj || obj->is(MapKind_Native));
13.223 + return reinterpret_cast<Native *>(obj);
13.224 + }
13.225 +};
13.226 +
13.227 +}
13.228 +
13.229 +#endif // _include_jitcraft_function_h_
14.1 --- a/src/Interpreter.cpp Mon Jun 10 00:46:29 2013 +0100
14.2 +++ b/src/Interpreter.cpp Mon Jun 10 01:04:43 2013 +0100
14.3 @@ -1,1041 +1,1041 @@
14.4 -/* vim: set ts=4 sw=4 tw=99 et:
14.5 - *
14.6 - * Copyright (C) 2012 David Anderson
14.7 - *
14.8 - * This file is part of JITCraft.
14.9 - *
14.10 - * JITCraft is free software: you can redistribute it and/or modify it under
14.11 - * the terms of the GNU General Public License as published by the Free
14.12 - * Software Foundation, either version 3 of the License, or (at your option)
14.13 - * any later version.
14.14 - *
14.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
14.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14.18 - *
14.19 - * You should have received a copy of the GNU General Public License along with
14.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
14.21 - */
14.22 -#include <string.h>
14.23 -#include "Interpreter.h"
14.24 -#include "Modules.h"
14.25 -#include "Zone.h"
14.26 -#include "Types.h"
14.27 -#include "Array.h"
14.28 -#include "Reference.h"
14.29 -#include "Strings.h"
14.30 -#include "Environments.h"
14.31 -#include "Structures.h"
14.32 -#include "NativeTable.h"
14.33 -#include "Packages.h"
14.34 -#include "Heap-inl.h"
14.35 -
14.36 -using namespace ke;
14.37 -
14.38 -#define PUSH_I32(top, value) \
14.39 - do { \
14.40 - top.sp->i32 = value; \
14.41 - top.sp++; \
14.42 - } while (0)
14.43 -
14.44 -#define PUSH_F(top, value) \
14.45 - do { \
14.46 - top.sp->f = value; \
14.47 - top.sp++; \
14.48 - } while (0)
14.49 -
14.50 -static inline int
14.51 -POP_I32(Top &top)
14.52 -{
14.53 - int value = top.sp[-1].i32;
14.54 - top.sp--;
14.55 - return value;
14.56 -}
14.57 -
14.58 -static inline float
14.59 -POP_F(Top &top)
14.60 -{
14.61 - float value = top.sp[-1].f;
14.62 - top.sp--;
14.63 - return value;
14.64 -}
14.65 -
14.66 -// Pawn's original semantics specify some kind of floor operation, so
14.67 -// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
14.68 -// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
14.69 -// does not. My guess is that Borja freaked out seeing the 13-instruction x86
14.70 -// sequence necessary to get this functionality (I vaguely recall a thread
14.71 -// where we discussed this with Mark Peter? But the ITB forums are gone...),
14.72 -// and we just decided to break the damn thing. So SP1 was inconsistent, but
14.73 -// we are not. And for completeness, we assert that the C compiler does the
14.74 -// right thing, since C89 leaves it unspecified.
14.75 -STATIC_ASSERT(8 / -3 == -2);
14.76 -STATIC_ASSERT(-8 / 3 == -2);
14.77 -
14.78 -static inline bool
14.79 -PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
14.80 -{
14.81 - Reference *ref = Reference::NewStack(zone, location, tenure);
14.82 - if (!ref)
14.83 - return false;
14.84 - top.sp->ref = ref;
14.85 - top.sp++;
14.86 - return true;
14.87 -}
14.88 -
14.89 -static void
14.90 -GetElement(Array *array, int index, LocalSlot *vp)
14.91 -{
14.92 - if (array->type()->contained()->isTraceable()) {
14.93 - vp->obj = array->readObject(index);
14.94 - return;
14.95 - }
14.96 -
14.97 - switch (array->type()->contained()->pod()) {
14.98 - case PrimitiveType_Float:
14.99 - vp->f = array->readFloat(index);
14.100 - break;
14.101 -
14.102 - case PrimitiveType_Char:
14.103 - vp->i32 = array->readChar(index);
14.104 - break;
14.105 -
14.106 - default:
14.107 - assert(array->type()->contained()->pod() == PrimitiveType_Int32);
14.108 - vp->i32 = array->readInt32(index);
14.109 - break;
14.110 - }
14.111 -}
14.112 -
14.113 -static void
14.114 -SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
14.115 -{
14.116 - if (array->type()->contained()->isTraceable()) {
14.117 - array->writeObject(zone, index, v.obj);
14.118 - return;
14.119 - }
14.120 -
14.121 - switch (array->type()->contained()->pod()) {
14.122 - case PrimitiveType_Float:
14.123 - array->writeFloat(index, v.f);
14.124 - break;
14.125 -
14.126 - case PrimitiveType_Char:
14.127 - array->writeChar(index, v.i32);
14.128 - break;
14.129 -
14.130 - default:
14.131 - assert(array->type()->contained()->pod() == PrimitiveType_Int32);
14.132 - array->writeInt32(index, v.i32);
14.133 - break;
14.134 - }
14.135 -}
14.136 -
14.137 -static void
14.138 -FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
14.139 -{
14.140 - // :TODO: assert no GC.
14.141 - if (desc->type()->isTraceable()) {
14.142 - vp->obj = obj->get<Object *>(desc);
14.143 - return;
14.144 - }
14.145 -
14.146 - switch (desc->type()->pod()) {
14.147 - case PrimitiveType_Float:
14.148 - vp->f = obj->get<float>(desc);
14.149 - break;
14.150 -
14.151 - default:
14.152 - assert(desc->type()->pod() == PrimitiveType_Int32);
14.153 - vp->i32 = obj->get<int>(desc);
14.154 - break;
14.155 - }
14.156 -}
14.157 -
14.158 -static void
14.159 -GetField(Struct *obj, unsigned index, LocalSlot *vp)
14.160 -{
14.161 - StructType *type = StructType::cast(obj->map()->type());
14.162 - Descriptor *desc = Descriptor::cast(type->fields()->at(index));
14.163 - FetchField(obj, desc, vp);
14.164 -}
14.165 -
14.166 -static void
14.167 -GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
14.168 -{
14.169 - Local<StructType> type(zone, StructType::cast(obj->map()->type()));
14.170 - Local<Descriptor> desc(zone, type->lookupField(name, NULL));
14.171 - FetchField(obj, desc, vp);
14.172 -}
14.173 -
14.174 -static void
14.175 -StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
14.176 -{
14.177 - // :TODO: assert no GC.
14.178 - if (desc->type()->isTraceable()) {
14.179 - obj->set(zone, desc, v.obj);
14.180 - return;
14.181 - }
14.182 -
14.183 - switch (desc->type()->pod()) {
14.184 - case PrimitiveType_Float:
14.185 - obj->set<float>(desc, v.f);
14.186 - break;
14.187 -
14.188 - default:
14.189 - assert(desc->type()->pod() == PrimitiveType_Int32);
14.190 - obj->set<int>(desc, v.i32);
14.191 - break;
14.192 - }
14.193 -}
14.194 -
14.195 -static void
14.196 -SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
14.197 -{
14.198 - StructType *type = StructType::cast(obj->map()->type());
14.199 - Descriptor *desc = Descriptor::cast(type->fields()->at(index));
14.200 - StoreField(zone, obj, desc, v);
14.201 -}
14.202 -
14.203 -static void
14.204 -SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
14.205 -{
14.206 - Local<StructType> type(zone, StructType::cast(obj->map()->type()));
14.207 - Local<Descriptor> desc(zone, type->lookupField(name, NULL));
14.208 - StoreField(zone, obj, desc, v);
14.209 -}
14.210 -
14.211 -static bool
14.212 -InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
14.213 - int *result)
14.214 -{
14.215 - NativeArgs guard;
14.216 -
14.217 - void *address = zone->nativeTable()->address(native->index());
14.218 - if (!address) {
14.219 - Local<String> name(zone, zone->nativeTable()->name(native->index()));
14.220 - zone->reportError(Message_NativeNotBound, name->chars());
14.221 - return false;
14.222 - }
14.223 -
14.224 - if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
14.225 - return false;
14.226 -
14.227 - intptr_t *cells = guard.args();
14.228 -
14.229 - // params[0] == argc, in ISPE
14.230 - cells[0] = argc;
14.231 -
14.232 - // Pass the formal arguments.
14.233 - Local<FunctionType> type(zone, native->type());
14.234 - Local<Type> param(zone);
14.235 - for (unsigned i = 0; i < type->parameters()->length(); i++) {
14.236 - param = type->parameterAt(i);
14.237 -
14.238 - // For floats, we rely on the aliasing of |i32| and |f|.
14.239 - LocalSlot &arg = args[-int(i) - 1];
14.240 - if (param->isInt32() || param->isFloat()) {
14.241 - cells[i + 1] = arg.i32;
14.242 - } else if (param->isReference()) {
14.243 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
14.244 - } else {
14.245 - assert(param->isArray());
14.246 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
14.247 - }
14.248 - }
14.249 -
14.250 - // For variadic arguments, the compiler left either arrays or references.
14.251 - for (unsigned i = type->parameters()->length(); i < argc; i++) {
14.252 - LocalSlot &arg = args[-int(i) - 1];
14.253 -
14.254 - if (arg.obj->is(MapKind_Reference)) {
14.255 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
14.256 - } else {
14.257 - assert(arg.obj->is(MapKind_Array));
14.258 - cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
14.259 - }
14.260 - }
14.261 -
14.262 - typedef intptr_t (*INVOKE)(void *, intptr_t *);
14.263 - INVOKE invoke = (INVOKE)address;
14.264 - *result = invoke(identity, cells);
14.265 -
14.266 - return !zone->hasPendingException();
14.267 -}
14.268 -
14.269 -bool
14.270 -ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
14.271 -{
14.272 - Top &top = *zone->stack().top();
14.273 - if (!entryFrame)
14.274 - entryFrame = top.fp;
14.275 -
14.276 - LocalSlot *locals = entryFrame->locals();
14.277 -
14.278 - for (;;) {
14.279 - Opcode op = Opcode(*top.pc);
14.280 -
14.281 - if (OpcodeInfo[op].nuses > 0)
14.282 - assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
14.283 -
14.284 - switch (op) {
14.285 -
14.286 -case OP_NOP:
14.287 - break;
14.288 -
14.289 -case OP_INT:
14.290 - PUSH_I32(top, READ_INT32(top.pc));
14.291 - break;
14.292 -
14.293 -case OP_FLOAT:
14.294 - PUSH_F(top, READ_FLOAT(top.pc));
14.295 - break;
14.296 -
14.297 -case OP_RETURN:
14.298 -case OP_RETURNVOID:
14.299 -case OP_STOP:
14.300 -{
14.301 - if (op == OP_RETURN)
14.302 - *result = *--top.sp;
14.303 -
14.304 - if (top.fp == entryFrame)
14.305 - goto done;
14.306 -
14.307 - // This must not GC.
14.308 - zone->stack().popInlineFrame();
14.309 - locals = top.fp->locals();
14.310 -
14.311 - if (op == OP_RETURN)
14.312 - *top.sp++ = *result;
14.313 -
14.314 - top.pc += OpcodeInfo[*top.pc].length;
14.315 - continue;
14.316 -}
14.317 -
14.318 -case OP_POP:
14.319 -{
14.320 - top.sp--;
14.321 - break;
14.322 -}
14.323 -
14.324 -case OP_JT:
14.325 -{
14.326 - int value = POP_I32(top);
14.327 - if (value) {
14.328 - top.pc += READ_INT32(top.pc);
14.329 - continue;
14.330 - }
14.331 - break;
14.332 -}
14.333 -
14.334 -case OP_JF:
14.335 -{
14.336 - int value = POP_I32(top);
14.337 - if (!value) {
14.338 - top.pc += READ_INT32(top.pc);
14.339 - continue;
14.340 - }
14.341 - break;
14.342 -}
14.343 -
14.344 -case OP_JUMP:
14.345 -{
14.346 - top.pc += READ_INT32(top.pc);
14.347 - continue;
14.348 -}
14.349 -
14.350 -case OP_BREAK:
14.351 -case OP_CONTINUE:
14.352 -{
14.353 - top.fp->leaveLoop(zone);
14.354 - top.pc += READ_INT32(top.pc);
14.355 - continue;
14.356 -}
14.357 -
14.358 -case OP_GETLOCAL:
14.359 -{
14.360 - unsigned slot = READ_UINT32(top.pc);
14.361 - assert(slot < top.fp->code()->nlocals());
14.362 - *top.sp++ = locals[slot];
14.363 - break;
14.364 -}
14.365 -
14.366 -case OP_SETLOCAL:
14.367 -{
14.368 - unsigned slot = READ_UINT32(top.pc);
14.369 - assert(slot < top.fp->code()->nlocals());
14.370 - locals[slot] = top.sp[-1];
14.371 - break;
14.372 -}
14.373 -
14.374 -case OP_ADD:
14.375 -{
14.376 - top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
14.377 - top.sp--;
14.378 - break;
14.379 -}
14.380 -
14.381 -case OP_SUB:
14.382 -{
14.383 - top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
14.384 - top.sp--;
14.385 - break;
14.386 -}
14.387 -
14.388 -case OP_MUL:
14.389 -{
14.390 - top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
14.391 - top.sp--;
14.392 - break;
14.393 -}
14.394 -
14.395 -case OP_DIV:
14.396 -{
14.397 - if (top.sp[-1].i32 == 0) {
14.398 - zone->reportError(Message_IntegerDivideByZero);
14.399 - goto error;
14.400 - }
14.401 - top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
14.402 - top.sp--;
14.403 - break;
14.404 -}
14.405 -
14.406 -case OP_MOD:
14.407 -{
14.408 - if (top.sp[-1].i32 == 0) {
14.409 - zone->reportError(Message_IntegerDivideByZero);
14.410 - goto error;
14.411 - }
14.412 - top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
14.413 - top.sp--;
14.414 - break;
14.415 -}
14.416 -
14.417 -case OP_LT:
14.418 -{
14.419 - top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
14.420 - top.sp--;
14.421 - break;
14.422 -}
14.423 -
14.424 -case OP_LE:
14.425 -{
14.426 - top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
14.427 - top.sp--;
14.428 - break;
14.429 -}
14.430 -
14.431 -case OP_GT:
14.432 -{
14.433 - top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
14.434 - top.sp--;
14.435 - break;
14.436 -}
14.437 -
14.438 -case OP_GE:
14.439 -{
14.440 - top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
14.441 - top.sp--;
14.442 - break;
14.443 -}
14.444 -
14.445 -case OP_EQ:
14.446 -{
14.447 - top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
14.448 - top.sp--;
14.449 - break;
14.450 -}
14.451 -
14.452 -case OP_NE:
14.453 -{
14.454 - top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
14.455 - top.sp--;
14.456 - break;
14.457 -}
14.458 -
14.459 -case OP_ADD_F:
14.460 -{
14.461 - top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
14.462 - top.sp--;
14.463 - break;
14.464 -}
14.465 -
14.466 -case OP_SUB_F:
14.467 -{
14.468 - top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
14.469 - top.sp--;
14.470 - break;
14.471 -}
14.472 -
14.473 -case OP_MUL_F:
14.474 -{
14.475 - top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
14.476 - top.sp--;
14.477 - break;
14.478 -}
14.479 -
14.480 -case OP_DIV_F:
14.481 -{
14.482 - top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
14.483 - top.sp--;
14.484 - break;
14.485 -}
14.486 -
14.487 -case OP_LT_F:
14.488 -{
14.489 - top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
14.490 - top.sp--;
14.491 - break;
14.492 -}
14.493 -
14.494 -case OP_LE_F:
14.495 -{
14.496 - top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
14.497 - top.sp--;
14.498 - break;
14.499 -}
14.500 -
14.501 -case OP_GT_F:
14.502 -{
14.503 - top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
14.504 - top.sp--;
14.505 - break;
14.506 -}
14.507 -
14.508 -case OP_GE_F:
14.509 -{
14.510 - top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
14.511 - top.sp--;
14.512 - break;
14.513 -}
14.514 -
14.515 -case OP_EQ_F:
14.516 -{
14.517 - top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
14.518 - top.sp--;
14.519 - break;
14.520 -}
14.521 -
14.522 -case OP_NE_F:
14.523 -{
14.524 - top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
14.525 - top.sp--;
14.526 - break;
14.527 -}
14.528 -
14.529 -case OP_SHL:
14.530 -{
14.531 - top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
14.532 - top.sp--;
14.533 - break;
14.534 -}
14.535 -
14.536 -case OP_SHR:
14.537 -{
14.538 - top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
14.539 - top.sp--;
14.540 - break;
14.541 -}
14.542 -
14.543 -case OP_USHR:
14.544 -{
14.545 - top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
14.546 - top.sp--;
14.547 - break;
14.548 -}
14.549 -
14.550 -case OP_BITAND:
14.551 -{
14.552 - top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
14.553 - top.sp--;
14.554 - break;
14.555 -}
14.556 -
14.557 -case OP_BITOR:
14.558 -{
14.559 - top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
14.560 - top.sp--;
14.561 - break;
14.562 -}
14.563 -
14.564 -case OP_BITXOR:
14.565 -{
14.566 - top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
14.567 - top.sp--;
14.568 - break;
14.569 -}
14.570 -
14.571 -case OP_BITNOT:
14.572 -{
14.573 - top.sp[-1].i32 = ~top.sp[-1].i32;
14.574 - break;
14.575 -}
14.576 -
14.577 -case OP_NOT:
14.578 -{
14.579 - top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
14.580 - break;
14.581 -}
14.582 -
14.583 -case OP_NOT_F:
14.584 -{
14.585 - top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
14.586 - break;
14.587 -}
14.588 -
14.589 -case OP_NEG:
14.590 -{
14.591 - top.sp[-1].i32 = -top.sp[-1].i32;
14.592 - break;
14.593 -}
14.594 -
14.595 -case OP_NEG_F:
14.596 -{
14.597 - top.sp[-1].f = -top.sp[-1].f;
14.598 - break;
14.599 -}
14.600 -
14.601 -case OP_CALL:
14.602 -{
14.603 - Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
14.604 - top.sp--;
14.605 -
14.606 - if (!zone->stack().pushInlineFrame(newFun))
14.607 - goto error;
14.608 -
14.609 - locals = top.fp->locals();
14.610 - continue;
14.611 -}
14.612 -
14.613 -case OP_GETARG:
14.614 -{
14.615 - unsigned slot = READ_UINT32(top.pc);
14.616 - *top.sp++ = top.fp->arg(slot);
14.617 - break;
14.618 -}
14.619 -
14.620 -case OP_SETARG:
14.621 -{
14.622 - unsigned slot = READ_UINT32(top.pc);
14.623 - top.fp->arg(slot) = top.sp[-1];
14.624 - break;
14.625 -}
14.626 -
14.627 -case OP_GETELEM:
14.628 -{
14.629 - Array *array = Array::cast(top.sp[-2].obj);
14.630 - int index = top.sp[-1].i32;
14.631 -
14.632 - if (index < 0 || unsigned(index) >= array->length()) {
14.633 - zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
14.634 - goto error;
14.635 - }
14.636 -
14.637 - GetElement(array, index, &top.sp[-2]);
14.638 - top.sp--;
14.639 - break;
14.640 -}
14.641 -
14.642 -case OP_SETELEM:
14.643 -{
14.644 - Array *array = Array::cast(top.sp[-3].obj);
14.645 - int index = top.sp[-2].i32;
14.646 -
14.647 - if (index < 0 || unsigned(index) >= array->length()) {
14.648 - zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
14.649 - goto error;
14.650 - }
14.651 -
14.652 - SetElement(zone, array, index, top.sp[-1]);
14.653 - top.sp[-3] = top.sp[-1];
14.654 - top.sp -= 2;
14.655 - break;
14.656 -}
14.657 -
14.658 -case OP_CVT_I2F:
14.659 -{
14.660 - int ival = POP_I32(top);
14.661 - float fval = (float)ival;
14.662 - PUSH_F(top, fval);
14.663 - break;
14.664 -}
14.665 -
14.666 -case OP_CVT_I2B:
14.667 -{
14.668 - top.sp[-1].i32 = !!top.sp[-1].i32;
14.669 - break;
14.670 -}
14.671 -
14.672 -case OP_DUPARRAY:
14.673 -{
14.674 - Local<Array> src(zone, Array::cast(top.sp[-1].obj));
14.675 - top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
14.676 - if (!top.sp[-1].obj)
14.677 - goto error;
14.678 - break;
14.679 -}
14.680 -
14.681 -case OP_NEWFIXED:
14.682 -{
14.683 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.684 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.685 - Array *array = Array::NewFixed(zone, map, tenure);
14.686 - if (!array)
14.687 - goto error;
14.688 - top.sp->obj = array;
14.689 - top.sp++;
14.690 - break;
14.691 -}
14.692 -
14.693 -case OP_NEWEMPTY:
14.694 -{
14.695 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.696 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.697 - Array *array = Array::NewEmpty(zone, map, tenure);
14.698 - if (!array)
14.699 - goto error;
14.700 - top.sp->obj = array;
14.701 - top.sp++;
14.702 - break;
14.703 -}
14.704 -
14.705 -case OP_NEWSIZED:
14.706 -{
14.707 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.708 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.709 - assert(map->type()->levels() < MAX_ARRAY_DEPTH);
14.710 -
14.711 - int dims[MAX_ARRAY_DEPTH];
14.712 - for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
14.713 - dims[i] = POP_I32(top);
14.714 -
14.715 - Array *array = Array::NewSized(zone, map, dims, tenure);
14.716 - if (!array)
14.717 - goto error;
14.718 - top.sp->obj = array;
14.719 - top.sp++;
14.720 - break;
14.721 -}
14.722 -
14.723 -case OP_NEWSTRUCT:
14.724 -{
14.725 - Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.726 - Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.727 - top.sp->obj = Struct::New(zone, map, tenure);
14.728 - if (!top.sp->obj)
14.729 - goto error;
14.730 - top.sp++;
14.731 - break;
14.732 -}
14.733 -
14.734 -case OP_SAVELIFO:
14.735 -{
14.736 - unsigned slot = READ_UINT32(top.pc);
14.737 - locals[slot].address = zone->heap().lifoPosition();
14.738 - break;
14.739 -}
14.740 -
14.741 -case OP_UNWINDLIFO:
14.742 -{
14.743 - unsigned slot = READ_UINT32(top.pc);
14.744 - zone->heap().unwindLifo(locals[slot].address);
14.745 - break;
14.746 -}
14.747 -
14.748 -case OP_VARREF_LIFO:
14.749 -{
14.750 - unsigned slot = READ_UINT32(top.pc);
14.751 - if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
14.752 - goto error;
14.753 - break;
14.754 -}
14.755 -
14.756 -case OP_ARGREF_LIFO:
14.757 -{
14.758 - unsigned slot = READ_UINT32(top.pc);
14.759 - if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
14.760 - goto error;
14.761 - break;
14.762 -}
14.763 -
14.764 -case OP_SLOTREF_LIFO:
14.765 -{
14.766 - Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
14.767 - if (!ref)
14.768 - goto error;
14.769 - top.sp[-1].ref = ref;
14.770 - break;
14.771 -}
14.772 -
14.773 -case OP_GETREF_I:
14.774 -{
14.775 - top.sp[-1].i32 = top.sp[-1].ref->getInt();
14.776 - break;
14.777 -}
14.778 -
14.779 -case OP_SETREF_I:
14.780 -{
14.781 - top.sp[-2].ref->setInt(top.sp[-1].i32);
14.782 - top.sp[-2].i32 = top.sp[-1].i32;
14.783 - top.sp--;
14.784 - break;
14.785 -}
14.786 -
14.787 -case OP_GETREF_F:
14.788 -{
14.789 - top.sp[-1].f = top.sp[-1].ref->getFloat();
14.790 - break;
14.791 -}
14.792 -
14.793 -case OP_SETREF_F:
14.794 -{
14.795 - top.sp[-2].ref->setFloat(top.sp[-1].f);
14.796 - top.sp[-2].f = top.sp[-1].f;
14.797 - break;
14.798 -}
14.799 -
14.800 -case OP_OBJECT:
14.801 -{
14.802 - top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
14.803 - top.sp++;
14.804 - break;
14.805 -}
14.806 -
14.807 -case OP_COPYARRAY:
14.808 -{
14.809 - // Note for this assignment opcode, we return the left-hand side, not the
14.810 - // right, since in this case the result of the expression could be different.
14.811 - Local<Array> left(zone, Array::cast(top.sp[-2].array));
14.812 - Local<Array> right(zone, Array::cast(top.sp[-1].array));
14.813 - if (!Array::ShallowCopy(zone, left, right))
14.814 - goto error;
14.815 - top.sp--;
14.816 - break;
14.817 -}
14.818 -
14.819 -case OP_DUP:
14.820 -{
14.821 - top.sp++;
14.822 - top.sp[-1] = top.sp[-2];
14.823 - break;
14.824 -}
14.825 -
14.826 -case OP_DUP2:
14.827 -{
14.828 - top.sp += 2;
14.829 - top.sp[-2] = top.sp[-4];
14.830 - top.sp[-1] = top.sp[-3];
14.831 - break;
14.832 -}
14.833 -
14.834 -case OP_SWAP:
14.835 -{
14.836 - LocalSlot slot = top.sp[-2];
14.837 - top.sp[-2] = top.sp[-1];
14.838 - top.sp[-1] = slot;
14.839 - break;
14.840 -}
14.841 -
14.842 -case OP_ROLL3:
14.843 -{
14.844 - LocalSlot slot = top.sp[-3];
14.845 - top.sp[-3] = top.sp[-2];
14.846 - top.sp[-2] = top.sp[-1];
14.847 - top.sp[-1] = slot;
14.848 - break;
14.849 -}
14.850 -
14.851 -case OP_PICK2:
14.852 -{
14.853 - top.sp++;
14.854 - top.sp[-1] = top.sp[-3];
14.855 - break;
14.856 -}
14.857 -
14.858 -case OP_PICK3:
14.859 -{
14.860 - top.sp++;
14.861 - top.sp[-1] = top.sp[-4];
14.862 - break;
14.863 -}
14.864 -
14.865 -case OP_CALLNATIVE:
14.866 -{
14.867 - unsigned argc = READ_UINT32(top.pc);
14.868 -
14.869 - Local<Native> native(zone, Native::cast(top.sp[-1].obj));
14.870 - top.sp--;
14.871 -
14.872 - int result;
14.873 - void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
14.874 - if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
14.875 - goto error;
14.876 -
14.877 - top.sp -= argc;
14.878 - PUSH_I32(top, result);
14.879 - break;
14.880 -}
14.881 -
14.882 -case OP_BITCAST:
14.883 -{
14.884 - // Because the stack is a union, this is a no-op.
14.885 - break;
14.886 -}
14.887 -
14.888 -case OP_TRUE:
14.889 -{
14.890 - top.sp++;
14.891 - top.sp[-1].i32 = 1;
14.892 - break;
14.893 -}
14.894 -
14.895 -case OP_FALSE:
14.896 -{
14.897 - top.sp++;
14.898 - top.sp[-1].i32 = 0;
14.899 - break;
14.900 -}
14.901 -
14.902 -case OP_GETFIELD:
14.903 -{
14.904 - Struct *obj;
14.905 - if (top.sp[-1].obj->is(MapKind_Module))
14.906 - obj = Module::cast(top.sp[-1].obj)->globals();
14.907 - else
14.908 - obj = Struct::cast(top.sp[-1].obj);
14.909 - GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
14.910 - break;
14.911 -}
14.912 -
14.913 -case OP_SETFIELD:
14.914 -{
14.915 - Struct *obj = Struct::cast(top.sp[-2].obj);
14.916 - SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
14.917 - top.sp[-2] = top.sp[-1];
14.918 - top.sp--;
14.919 - break;
14.920 -}
14.921 -
14.922 -case OP_COPYSTRUCT:
14.923 -{
14.924 - Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
14.925 - Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
14.926 - if (!Struct::Copy(zone, left, right))
14.927 - goto error;
14.928 - top.sp[-2].obj = top.sp[-1].obj;
14.929 - top.sp--;
14.930 - break;
14.931 -}
14.932 -
14.933 -case OP_TABLESWITCH:
14.934 -{
14.935 - int value = top.sp[-1].i32;
14.936 - int low = READ_TABLESWITCH_LOW(top.pc);
14.937 - int high = READ_TABLESWITCH_HIGH(top.pc);
14.938 -
14.939 - top.sp--;
14.940 -
14.941 - unsigned index = unsigned(value - low);
14.942 - unsigned tablesize = TableSwitchEntries(low, high);
14.943 - if (index < tablesize) {
14.944 - top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
14.945 - top.pc += index * OP_JUMP_LENGTH;
14.946 - continue;
14.947 - }
14.948 - break;
14.949 -}
14.950 -
14.951 -case OP_SIZEOF:
14.952 -{
14.953 - Array *array = Array::cast(top.sp[-1].obj);
14.954 - top.sp[-1].i32 = array->length();
14.955 - break;
14.956 -}
14.957 -
14.958 -case OP_PUBLIC:
14.959 -{
14.960 - Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
14.961 - zone->registerPublic(fun);
14.962 - top.sp--;
14.963 - break;
14.964 -}
14.965 -
14.966 -case OP_SETGLOBAL:
14.967 -{
14.968 - Local<Code> code(zone, top.fp->code());
14.969 - Local<Struct> obj(zone, code->module()->globals());
14.970 - Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
14.971 - SetGlobal(zone, obj, name, top.sp[-1]);
14.972 - break;
14.973 -}
14.974 -
14.975 -case OP_GETGLOBAL:
14.976 -{
14.977 - Local<Code> code(zone, top.fp->code());
14.978 - Local<Struct> obj(zone, code->module()->globals());
14.979 - Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
14.980 - GetGlobal(zone, obj, name, top.sp);
14.981 - top.sp++;
14.982 - break;
14.983 -}
14.984 -
14.985 -case OP_ENTERLOOP:
14.986 -{
14.987 - top.fp->enterLoop(zone);
14.988 - break;
14.989 -}
14.990 -
14.991 -case OP_LEAVELOOP:
14.992 -{
14.993 - top.fp->leaveLoop(zone);
14.994 - break;
14.995 -}
14.996 -
14.997 -case OP_DEPARRAY:
14.998 -{
14.999 - Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
14.1000 - Local<Array> array(zone, Array::cast(top.sp[-2].obj));
14.1001 - int index = top.sp[-1].i32;
14.1002 -
14.1003 - // We allow taking 0-length dependent arrays.
14.1004 - if (index < 0 || unsigned(index) > array->length()) {
14.1005 - zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
14.1006 - goto error;
14.1007 - }
14.1008 -
14.1009 - top.sp[-2].obj = DependentArray::New(zone, array, map, index);
14.1010 - if (!top.sp[-2].obj)
14.1011 - goto error;
14.1012 -
14.1013 - top.sp--;
14.1014 - break;
14.1015 -}
14.1016 -
14.1017 -case OP_IMPORT:
14.1018 -{
14.1019 - unsigned index = READ_UINT32(top.pc);
14.1020 -
14.1021 - top.sp++;
14.1022 - top.sp[-1].obj = top.fp->code()->module()->getImportAt(index);
14.1023 - break;
14.1024 -}
14.1025 -
14.1026 -default:
14.1027 - assert(false);
14.1028 - return false;
14.1029 -
14.1030 - }
14.1031 -
14.1032 - top.pc += OpcodeInfo[op].length;
14.1033 - assert(top.sp >= top.fp->stackBase());
14.1034 - }
14.1035 -
14.1036 -done:
14.1037 - return true;
14.1038 -
14.1039 -error:
14.1040 - // Unwind frames until we can continue.
14.1041 - while (top.fp != entryFrame)
14.1042 - zone->stack().popInlineFrame();
14.1043 - return false;
14.1044 -}
14.1045 +/* vim: set ts=4 sw=4 tw=99 et:
14.1046 + *
14.1047 + * Copyright (C) 2012 David Anderson
14.1048 + *
14.1049 + * This file is part of JITCraft.
14.1050 + *
14.1051 + * JITCraft is free software: you can redistribute it and/or modify it under
14.1052 + * the terms of the GNU General Public License as published by the Free
14.1053 + * Software Foundation, either version 3 of the License, or (at your option)
14.1054 + * any later version.
14.1055 + *
14.1056 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
14.1057 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14.1058 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14.1059 + *
14.1060 + * You should have received a copy of the GNU General Public License along with
14.1061 + * JITCraft. If not, see http://www.gnu.org/licenses/.
14.1062 + */
14.1063 +#include <string.h>
14.1064 +#include "Interpreter.h"
14.1065 +#include "Modules.h"
14.1066 +#include "Zone.h"
14.1067 +#include "Types.h"
14.1068 +#include "Array.h"
14.1069 +#include "Reference.h"
14.1070 +#include "Strings.h"
14.1071 +#include "Environments.h"
14.1072 +#include "Structures.h"
14.1073 +#include "NativeTable.h"
14.1074 +#include "Packages.h"
14.1075 +#include "Heap-inl.h"
14.1076 +
14.1077 +using namespace ke;
14.1078 +
14.1079 +#define PUSH_I32(top, value) \
14.1080 + do { \
14.1081 + top.sp->i32 = value; \
14.1082 + top.sp++; \
14.1083 + } while (0)
14.1084 +
14.1085 +#define PUSH_F(top, value) \
14.1086 + do { \
14.1087 + top.sp->f = value; \
14.1088 + top.sp++; \
14.1089 + } while (0)
14.1090 +
14.1091 +static inline int
14.1092 +POP_I32(Top &top)
14.1093 +{
14.1094 + int value = top.sp[-1].i32;
14.1095 + top.sp--;
14.1096 + return value;
14.1097 +}
14.1098 +
14.1099 +static inline float
14.1100 +POP_F(Top &top)
14.1101 +{
14.1102 + float value = top.sp[-1].f;
14.1103 + top.sp--;
14.1104 + return value;
14.1105 +}
14.1106 +
14.1107 +// Pawn's original semantics specify some kind of floor operation, so
14.1108 +// (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
14.1109 +// the upstream algorithm when constant folding. However the SourcePawn 1 JIT
14.1110 +// does not. My guess is that Borja freaked out seeing the 13-instruction x86
14.1111 +// sequence necessary to get this functionality (I vaguely recall a thread
14.1112 +// where we discussed this with Mark Peter? But the ITB forums are gone...),
14.1113 +// and we just decided to break the damn thing. So SP1 was inconsistent, but
14.1114 +// we are not. And for completeness, we assert that the C compiler does the
14.1115 +// right thing, since C89 leaves it unspecified.
14.1116 +STATIC_ASSERT(8 / -3 == -2);
14.1117 +STATIC_ASSERT(-8 / 3 == -2);
14.1118 +
14.1119 +static inline bool
14.1120 +PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
14.1121 +{
14.1122 + Reference *ref = Reference::NewStack(zone, location, tenure);
14.1123 + if (!ref)
14.1124 + return false;
14.1125 + top.sp->ref = ref;
14.1126 + top.sp++;
14.1127 + return true;
14.1128 +}
14.1129 +
14.1130 +static void
14.1131 +GetElement(Array *array, int index, LocalSlot *vp)
14.1132 +{
14.1133 + if (array->type()->contained()->isTraceable()) {
14.1134 + vp->obj = array->readObject(index);
14.1135 + return;
14.1136 + }
14.1137 +
14.1138 + switch (array->type()->contained()->pod()) {
14.1139 + case PrimitiveType_Float:
14.1140 + vp->f = array->readFloat(index);
14.1141 + break;
14.1142 +
14.1143 + case PrimitiveType_Char:
14.1144 + vp->i32 = array->readChar(index);
14.1145 + break;
14.1146 +
14.1147 + default:
14.1148 + assert(array->type()->contained()->pod() == PrimitiveType_Int32);
14.1149 + vp->i32 = array->readInt32(index);
14.1150 + break;
14.1151 + }
14.1152 +}
14.1153 +
14.1154 +static void
14.1155 +SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
14.1156 +{
14.1157 + if (array->type()->contained()->isTraceable()) {
14.1158 + array->writeObject(zone, index, v.obj);
14.1159 + return;
14.1160 + }
14.1161 +
14.1162 + switch (array->type()->contained()->pod()) {
14.1163 + case PrimitiveType_Float:
14.1164 + array->writeFloat(index, v.f);
14.1165 + break;
14.1166 +
14.1167 + case PrimitiveType_Char:
14.1168 + array->writeChar(index, v.i32);
14.1169 + break;
14.1170 +
14.1171 + default:
14.1172 + assert(array->type()->contained()->pod() == PrimitiveType_Int32);
14.1173 + array->writeInt32(index, v.i32);
14.1174 + break;
14.1175 + }
14.1176 +}
14.1177 +
14.1178 +static void
14.1179 +FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
14.1180 +{
14.1181 + // :TODO: assert no GC.
14.1182 + if (desc->type()->isTraceable()) {
14.1183 + vp->obj = obj->get<Object *>(desc);
14.1184 + return;
14.1185 + }
14.1186 +
14.1187 + switch (desc->type()->pod()) {
14.1188 + case PrimitiveType_Float:
14.1189 + vp->f = obj->get<float>(desc);
14.1190 + break;
14.1191 +
14.1192 + default:
14.1193 + assert(desc->type()->pod() == PrimitiveType_Int32);
14.1194 + vp->i32 = obj->get<int>(desc);
14.1195 + break;
14.1196 + }
14.1197 +}
14.1198 +
14.1199 +static void
14.1200 +GetField(Struct *obj, unsigned index, LocalSlot *vp)
14.1201 +{
14.1202 + StructType *type = StructType::cast(obj->map()->type());
14.1203 + Descriptor *desc = Descriptor::cast(type->fields()->at(index));
14.1204 + FetchField(obj, desc, vp);
14.1205 +}
14.1206 +
14.1207 +static void
14.1208 +GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
14.1209 +{
14.1210 + Local<StructType> type(zone, StructType::cast(obj->map()->type()));
14.1211 + Local<Descriptor> desc(zone, type->lookupField(name, NULL));
14.1212 + FetchField(obj, desc, vp);
14.1213 +}
14.1214 +
14.1215 +static void
14.1216 +StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
14.1217 +{
14.1218 + // :TODO: assert no GC.
14.1219 + if (desc->type()->isTraceable()) {
14.1220 + obj->set(zone, desc, v.obj);
14.1221 + return;
14.1222 + }
14.1223 +
14.1224 + switch (desc->type()->pod()) {
14.1225 + case PrimitiveType_Float:
14.1226 + obj->set<float>(desc, v.f);
14.1227 + break;
14.1228 +
14.1229 + default:
14.1230 + assert(desc->type()->pod() == PrimitiveType_Int32);
14.1231 + obj->set<int>(desc, v.i32);
14.1232 + break;
14.1233 + }
14.1234 +}
14.1235 +
14.1236 +static void
14.1237 +SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
14.1238 +{
14.1239 + StructType *type = StructType::cast(obj->map()->type());
14.1240 + Descriptor *desc = Descriptor::cast(type->fields()->at(index));
14.1241 + StoreField(zone, obj, desc, v);
14.1242 +}
14.1243 +
14.1244 +static void
14.1245 +SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
14.1246 +{
14.1247 + Local<StructType> type(zone, StructType::cast(obj->map()->type()));
14.1248 + Local<Descriptor> desc(zone, type->lookupField(name, NULL));
14.1249 + StoreField(zone, obj, desc, v);
14.1250 +}
14.1251 +
14.1252 +static bool
14.1253 +InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
14.1254 + int *result)
14.1255 +{
14.1256 + NativeArgs guard;
14.1257 +
14.1258 + void *address = zone->nativeTable()->address(native->index());
14.1259 + if (!address) {
14.1260 + Local<String> name(zone, zone->nativeTable()->name(native->index()));
14.1261 + zone->reportError(Message_NativeNotBound, name->chars());
14.1262 + return false;
14.1263 + }
14.1264 +
14.1265 + if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
14.1266 + return false;
14.1267 +
14.1268 + intptr_t *cells = guard.args();
14.1269 +
14.1270 + // params[0] == argc, in ISPE
14.1271 + cells[0] = argc;
14.1272 +
14.1273 + // Pass the formal arguments.
14.1274 + Local<FunctionType> type(zone, native->type());
14.1275 + Local<Type> param(zone);
14.1276 + for (unsigned i = 0; i < type->parameters()->length(); i++) {
14.1277 + param = type->parameterAt(i);
14.1278 +
14.1279 + // For floats, we rely on the aliasing of |i32| and |f|.
14.1280 + LocalSlot &arg = args[-int(i) - 1];
14.1281 + if (param->isInt32() || param->isFloat()) {
14.1282 + cells[i + 1] = arg.i32;
14.1283 + } else if (param->isReference()) {
14.1284 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
14.1285 + } else {
14.1286 + assert(param->isArray());
14.1287 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
14.1288 + }
14.1289 + }
14.1290 +
14.1291 + // For variadic arguments, the compiler left either arrays or references.
14.1292 + for (unsigned i = type->parameters()->length(); i < argc; i++) {
14.1293 + LocalSlot &arg = args[-int(i) - 1];
14.1294 +
14.1295 + if (arg.obj->is(MapKind_Reference)) {
14.1296 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
14.1297 + } else {
14.1298 + assert(arg.obj->is(MapKind_Array));
14.1299 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
14.1300 + }
14.1301 + }
14.1302 +
14.1303 + typedef intptr_t (*INVOKE)(void *, intptr_t *);
14.1304 + INVOKE invoke = (INVOKE)address;
14.1305 + *result = invoke(identity, cells);
14.1306 +
14.1307 + return !zone->hasPendingException();
14.1308 +}
14.1309 +
14.1310 +bool
14.1311 +ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
14.1312 +{
14.1313 + Top &top = *zone->stack().top();
14.1314 + if (!entryFrame)
14.1315 + entryFrame = top.fp;
14.1316 +
14.1317 + LocalSlot *locals = entryFrame->locals();
14.1318 +
14.1319 + for (;;) {
14.1320 + Opcode op = Opcode(*top.pc);
14.1321 +
14.1322 + if (OpcodeInfo[op].nuses > 0)
14.1323 + assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
14.1324 +
14.1325 + switch (op) {
14.1326 +
14.1327 +case OP_NOP:
14.1328 + break;
14.1329 +
14.1330 +case OP_INT:
14.1331 + PUSH_I32(top, READ_INT32(top.pc));
14.1332 + break;
14.1333 +
14.1334 +case OP_FLOAT:
14.1335 + PUSH_F(top, READ_FLOAT(top.pc));
14.1336 + break;
14.1337 +
14.1338 +case OP_RETURN:
14.1339 +case OP_RETURNVOID:
14.1340 +case OP_STOP:
14.1341 +{
14.1342 + if (op == OP_RETURN)
14.1343 + *result = *--top.sp;
14.1344 +
14.1345 + if (top.fp == entryFrame)
14.1346 + goto done;
14.1347 +
14.1348 + // This must not GC.
14.1349 + zone->stack().popInlineFrame();
14.1350 + locals = top.fp->locals();
14.1351 +
14.1352 + if (op == OP_RETURN)
14.1353 + *top.sp++ = *result;
14.1354 +
14.1355 + top.pc += OpcodeInfo[*top.pc].length;
14.1356 + continue;
14.1357 +}
14.1358 +
14.1359 +case OP_POP:
14.1360 +{
14.1361 + top.sp--;
14.1362 + break;
14.1363 +}
14.1364 +
14.1365 +case OP_JT:
14.1366 +{
14.1367 + int value = POP_I32(top);
14.1368 + if (value) {
14.1369 + top.pc += READ_INT32(top.pc);
14.1370 + continue;
14.1371 + }
14.1372 + break;
14.1373 +}
14.1374 +
14.1375 +case OP_JF:
14.1376 +{
14.1377 + int value = POP_I32(top);
14.1378 + if (!value) {
14.1379 + top.pc += READ_INT32(top.pc);
14.1380 + continue;
14.1381 + }
14.1382 + break;
14.1383 +}
14.1384 +
14.1385 +case OP_JUMP:
14.1386 +{
14.1387 + top.pc += READ_INT32(top.pc);
14.1388 + continue;
14.1389 +}
14.1390 +
14.1391 +case OP_BREAK:
14.1392 +case OP_CONTINUE:
14.1393 +{
14.1394 + top.fp->leaveLoop(zone);
14.1395 + top.pc += READ_INT32(top.pc);
14.1396 + continue;
14.1397 +}
14.1398 +
14.1399 +case OP_GETLOCAL:
14.1400 +{
14.1401 + unsigned slot = READ_UINT32(top.pc);
14.1402 + assert(slot < top.fp->code()->nlocals());
14.1403 + *top.sp++ = locals[slot];
14.1404 + break;
14.1405 +}
14.1406 +
14.1407 +case OP_SETLOCAL:
14.1408 +{
14.1409 + unsigned slot = READ_UINT32(top.pc);
14.1410 + assert(slot < top.fp->code()->nlocals());
14.1411 + locals[slot] = top.sp[-1];
14.1412 + break;
14.1413 +}
14.1414 +
14.1415 +case OP_ADD:
14.1416 +{
14.1417 + top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
14.1418 + top.sp--;
14.1419 + break;
14.1420 +}
14.1421 +
14.1422 +case OP_SUB:
14.1423 +{
14.1424 + top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
14.1425 + top.sp--;
14.1426 + break;
14.1427 +}
14.1428 +
14.1429 +case OP_MUL:
14.1430 +{
14.1431 + top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
14.1432 + top.sp--;
14.1433 + break;
14.1434 +}
14.1435 +
14.1436 +case OP_DIV:
14.1437 +{
14.1438 + if (top.sp[-1].i32 == 0) {
14.1439 + zone->reportError(Message_IntegerDivideByZero);
14.1440 + goto error;
14.1441 + }
14.1442 + top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
14.1443 + top.sp--;
14.1444 + break;
14.1445 +}
14.1446 +
14.1447 +case OP_MOD:
14.1448 +{
14.1449 + if (top.sp[-1].i32 == 0) {
14.1450 + zone->reportError(Message_IntegerDivideByZero);
14.1451 + goto error;
14.1452 + }
14.1453 + top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
14.1454 + top.sp--;
14.1455 + break;
14.1456 +}
14.1457 +
14.1458 +case OP_LT:
14.1459 +{
14.1460 + top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
14.1461 + top.sp--;
14.1462 + break;
14.1463 +}
14.1464 +
14.1465 +case OP_LE:
14.1466 +{
14.1467 + top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
14.1468 + top.sp--;
14.1469 + break;
14.1470 +}
14.1471 +
14.1472 +case OP_GT:
14.1473 +{
14.1474 + top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
14.1475 + top.sp--;
14.1476 + break;
14.1477 +}
14.1478 +
14.1479 +case OP_GE:
14.1480 +{
14.1481 + top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
14.1482 + top.sp--;
14.1483 + break;
14.1484 +}
14.1485 +
14.1486 +case OP_EQ:
14.1487 +{
14.1488 + top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
14.1489 + top.sp--;
14.1490 + break;
14.1491 +}
14.1492 +
14.1493 +case OP_NE:
14.1494 +{
14.1495 + top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
14.1496 + top.sp--;
14.1497 + break;
14.1498 +}
14.1499 +
14.1500 +case OP_ADD_F:
14.1501 +{
14.1502 + top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
14.1503 + top.sp--;
14.1504 + break;
14.1505 +}
14.1506 +
14.1507 +case OP_SUB_F:
14.1508 +{
14.1509 + top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
14.1510 + top.sp--;
14.1511 + break;
14.1512 +}
14.1513 +
14.1514 +case OP_MUL_F:
14.1515 +{
14.1516 + top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
14.1517 + top.sp--;
14.1518 + break;
14.1519 +}
14.1520 +
14.1521 +case OP_DIV_F:
14.1522 +{
14.1523 + top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
14.1524 + top.sp--;
14.1525 + break;
14.1526 +}
14.1527 +
14.1528 +case OP_LT_F:
14.1529 +{
14.1530 + top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
14.1531 + top.sp--;
14.1532 + break;
14.1533 +}
14.1534 +
14.1535 +case OP_LE_F:
14.1536 +{
14.1537 + top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
14.1538 + top.sp--;
14.1539 + break;
14.1540 +}
14.1541 +
14.1542 +case OP_GT_F:
14.1543 +{
14.1544 + top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
14.1545 + top.sp--;
14.1546 + break;
14.1547 +}
14.1548 +
14.1549 +case OP_GE_F:
14.1550 +{
14.1551 + top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
14.1552 + top.sp--;
14.1553 + break;
14.1554 +}
14.1555 +
14.1556 +case OP_EQ_F:
14.1557 +{
14.1558 + top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
14.1559 + top.sp--;
14.1560 + break;
14.1561 +}
14.1562 +
14.1563 +case OP_NE_F:
14.1564 +{
14.1565 + top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
14.1566 + top.sp--;
14.1567 + break;
14.1568 +}
14.1569 +
14.1570 +case OP_SHL:
14.1571 +{
14.1572 + top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
14.1573 + top.sp--;
14.1574 + break;
14.1575 +}
14.1576 +
14.1577 +case OP_SHR:
14.1578 +{
14.1579 + top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
14.1580 + top.sp--;
14.1581 + break;
14.1582 +}
14.1583 +
14.1584 +case OP_USHR:
14.1585 +{
14.1586 + top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
14.1587 + top.sp--;
14.1588 + break;
14.1589 +}
14.1590 +
14.1591 +case OP_BITAND:
14.1592 +{
14.1593 + top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
14.1594 + top.sp--;
14.1595 + break;
14.1596 +}
14.1597 +
14.1598 +case OP_BITOR:
14.1599 +{
14.1600 + top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
14.1601 + top.sp--;
14.1602 + break;
14.1603 +}
14.1604 +
14.1605 +case OP_BITXOR:
14.1606 +{
14.1607 + top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
14.1608 + top.sp--;
14.1609 + break;
14.1610 +}
14.1611 +
14.1612 +case OP_BITNOT:
14.1613 +{
14.1614 + top.sp[-1].i32 = ~top.sp[-1].i32;
14.1615 + break;
14.1616 +}
14.1617 +
14.1618 +case OP_NOT:
14.1619 +{
14.1620 + top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
14.1621 + break;
14.1622 +}
14.1623 +
14.1624 +case OP_NOT_F:
14.1625 +{
14.1626 + top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
14.1627 + break;
14.1628 +}
14.1629 +
14.1630 +case OP_NEG:
14.1631 +{
14.1632 + top.sp[-1].i32 = -top.sp[-1].i32;
14.1633 + break;
14.1634 +}
14.1635 +
14.1636 +case OP_NEG_F:
14.1637 +{
14.1638 + top.sp[-1].f = -top.sp[-1].f;
14.1639 + break;
14.1640 +}
14.1641 +
14.1642 +case OP_CALL:
14.1643 +{
14.1644 + Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
14.1645 + top.sp--;
14.1646 +
14.1647 + if (!zone->stack().pushInlineFrame(newFun))
14.1648 + goto error;
14.1649 +
14.1650 + locals = top.fp->locals();
14.1651 + continue;
14.1652 +}
14.1653 +
14.1654 +case OP_GETARG:
14.1655 +{
14.1656 + unsigned slot = READ_UINT32(top.pc);
14.1657 + *top.sp++ = top.fp->arg(slot);
14.1658 + break;
14.1659 +}
14.1660 +
14.1661 +case OP_SETARG:
14.1662 +{
14.1663 + unsigned slot = READ_UINT32(top.pc);
14.1664 + top.fp->arg(slot) = top.sp[-1];
14.1665 + break;
14.1666 +}
14.1667 +
14.1668 +case OP_GETELEM:
14.1669 +{
14.1670 + Array *array = Array::cast(top.sp[-2].obj);
14.1671 + int index = top.sp[-1].i32;
14.1672 +
14.1673 + if (index < 0 || unsigned(index) >= array->length()) {
14.1674 + zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
14.1675 + goto error;
14.1676 + }
14.1677 +
14.1678 + GetElement(array, index, &top.sp[-2]);
14.1679 + top.sp--;
14.1680 + break;
14.1681 +}
14.1682 +
14.1683 +case OP_SETELEM:
14.1684 +{
14.1685 + Array *array = Array::cast(top.sp[-3].obj);
14.1686 + int index = top.sp[-2].i32;
14.1687 +
14.1688 + if (index < 0 || unsigned(index) >= array->length()) {
14.1689 + zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
14.1690 + goto error;
14.1691 + }
14.1692 +
14.1693 + SetElement(zone, array, index, top.sp[-1]);
14.1694 + top.sp[-3] = top.sp[-1];
14.1695 + top.sp -= 2;
14.1696 + break;
14.1697 +}
14.1698 +
14.1699 +case OP_CVT_I2F:
14.1700 +{
14.1701 + int ival = POP_I32(top);
14.1702 + float fval = (float)ival;
14.1703 + PUSH_F(top, fval);
14.1704 + break;
14.1705 +}
14.1706 +
14.1707 +case OP_CVT_I2B:
14.1708 +{
14.1709 + top.sp[-1].i32 = !!top.sp[-1].i32;
14.1710 + break;
14.1711 +}
14.1712 +
14.1713 +case OP_DUPARRAY:
14.1714 +{
14.1715 + Local<Array> src(zone, Array::cast(top.sp[-1].obj));
14.1716 + top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
14.1717 + if (!top.sp[-1].obj)
14.1718 + goto error;
14.1719 + break;
14.1720 +}
14.1721 +
14.1722 +case OP_NEWFIXED:
14.1723 +{
14.1724 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.1725 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.1726 + Array *array = Array::NewFixed(zone, map, tenure);
14.1727 + if (!array)
14.1728 + goto error;
14.1729 + top.sp->obj = array;
14.1730 + top.sp++;
14.1731 + break;
14.1732 +}
14.1733 +
14.1734 +case OP_NEWEMPTY:
14.1735 +{
14.1736 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.1737 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.1738 + Array *array = Array::NewEmpty(zone, map, tenure);
14.1739 + if (!array)
14.1740 + goto error;
14.1741 + top.sp->obj = array;
14.1742 + top.sp++;
14.1743 + break;
14.1744 +}
14.1745 +
14.1746 +case OP_NEWSIZED:
14.1747 +{
14.1748 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.1749 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.1750 + assert(map->type()->levels() < MAX_ARRAY_DEPTH);
14.1751 +
14.1752 + int dims[MAX_ARRAY_DEPTH];
14.1753 + for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
14.1754 + dims[i] = POP_I32(top);
14.1755 +
14.1756 + Array *array = Array::NewSized(zone, map, dims, tenure);
14.1757 + if (!array)
14.1758 + goto error;
14.1759 + top.sp->obj = array;
14.1760 + top.sp++;
14.1761 + break;
14.1762 +}
14.1763 +
14.1764 +case OP_NEWSTRUCT:
14.1765 +{
14.1766 + Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
14.1767 + Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
14.1768 + top.sp->obj = Struct::New(zone, map, tenure);
14.1769 + if (!top.sp->obj)
14.1770 + goto error;
14.1771 + top.sp++;
14.1772 + break;
14.1773 +}
14.1774 +
14.1775 +case OP_SAVELIFO:
14.1776 +{
14.1777 + unsigned slot = READ_UINT32(top.pc);
14.1778 + locals[slot].address = zone->heap().lifoPosition();
14.1779 + break;
14.1780 +}
14.1781 +
14.1782 +case OP_UNWINDLIFO:
14.1783 +{
14.1784 + unsigned slot = READ_UINT32(top.pc);
14.1785 + zone->heap().unwindLifo(locals[slot].address);
14.1786 + break;
14.1787 +}
14.1788 +
14.1789 +case OP_VARREF_LIFO:
14.1790 +{
14.1791 + unsigned slot = READ_UINT32(top.pc);
14.1792 + if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
14.1793 + goto error;
14.1794 + break;
14.1795 +}
14.1796 +
14.1797 +case OP_ARGREF_LIFO:
14.1798 +{
14.1799 + unsigned slot = READ_UINT32(top.pc);
14.1800 + if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
14.1801 + goto error;
14.1802 + break;
14.1803 +}
14.1804 +
14.1805 +case OP_SLOTREF_LIFO:
14.1806 +{
14.1807 + Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
14.1808 + if (!ref)
14.1809 + goto error;
14.1810 + top.sp[-1].ref = ref;
14.1811 + break;
14.1812 +}
14.1813 +
14.1814 +case OP_GETREF_I:
14.1815 +{
14.1816 + top.sp[-1].i32 = top.sp[-1].ref->getInt();
14.1817 + break;
14.1818 +}
14.1819 +
14.1820 +case OP_SETREF_I:
14.1821 +{
14.1822 + top.sp[-2].ref->setInt(top.sp[-1].i32);
14.1823 + top.sp[-2].i32 = top.sp[-1].i32;
14.1824 + top.sp--;
14.1825 + break;
14.1826 +}
14.1827 +
14.1828 +case OP_GETREF_F:
14.1829 +{
14.1830 + top.sp[-1].f = top.sp[-1].ref->getFloat();
14.1831 + break;
14.1832 +}
14.1833 +
14.1834 +case OP_SETREF_F:
14.1835 +{
14.1836 + top.sp[-2].ref->setFloat(top.sp[-1].f);
14.1837 + top.sp[-2].f = top.sp[-1].f;
14.1838 + break;
14.1839 +}
14.1840 +
14.1841 +case OP_OBJECT:
14.1842 +{
14.1843 + top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
14.1844 + top.sp++;
14.1845 + break;
14.1846 +}
14.1847 +
14.1848 +case OP_COPYARRAY:
14.1849 +{
14.1850 + // Note for this assignment opcode, we return the left-hand side, not the
14.1851 + // right, since in this case the result of the expression could be different.
14.1852 + Local<Array> left(zone, Array::cast(top.sp[-2].array));
14.1853 + Local<Array> right(zone, Array::cast(top.sp[-1].array));
14.1854 + if (!Array::ShallowCopy(zone, left, right))
14.1855 + goto error;
14.1856 + top.sp--;
14.1857 + break;
14.1858 +}
14.1859 +
14.1860 +case OP_DUP:
14.1861 +{
14.1862 + top.sp++;
14.1863 + top.sp[-1] = top.sp[-2];
14.1864 + break;
14.1865 +}
14.1866 +
14.1867 +case OP_DUP2:
14.1868 +{
14.1869 + top.sp += 2;
14.1870 + top.sp[-2] = top.sp[-4];
14.1871 + top.sp[-1] = top.sp[-3];
14.1872 + break;
14.1873 +}
14.1874 +
14.1875 +case OP_SWAP:
14.1876 +{
14.1877 + LocalSlot slot = top.sp[-2];
14.1878 + top.sp[-2] = top.sp[-1];
14.1879 + top.sp[-1] = slot;
14.1880 + break;
14.1881 +}
14.1882 +
14.1883 +case OP_ROLL3:
14.1884 +{
14.1885 + LocalSlot slot = top.sp[-3];
14.1886 + top.sp[-3] = top.sp[-2];
14.1887 + top.sp[-2] = top.sp[-1];
14.1888 + top.sp[-1] = slot;
14.1889 + break;
14.1890 +}
14.1891 +
14.1892 +case OP_PICK2:
14.1893 +{
14.1894 + top.sp++;
14.1895 + top.sp[-1] = top.sp[-3];
14.1896 + break;
14.1897 +}
14.1898 +
14.1899 +case OP_PICK3:
14.1900 +{
14.1901 + top.sp++;
14.1902 + top.sp[-1] = top.sp[-4];
14.1903 + break;
14.1904 +}
14.1905 +
14.1906 +case OP_CALLNATIVE:
14.1907 +{
14.1908 + unsigned argc = READ_UINT32(top.pc);
14.1909 +
14.1910 + Local<Native> native(zone, Native::cast(top.sp[-1].obj));
14.1911 + top.sp--;
14.1912 +
14.1913 + int result;
14.1914 + void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
14.1915 + if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
14.1916 + goto error;
14.1917 +
14.1918 + top.sp -= argc;
14.1919 + PUSH_I32(top, result);
14.1920 + break;
14.1921 +}
14.1922 +
14.1923 +case OP_BITCAST:
14.1924 +{
14.1925 + // Because the stack is a union, this is a no-op.
14.1926 + break;
14.1927 +}
14.1928 +
14.1929 +case OP_TRUE:
14.1930 +{
14.1931 + top.sp++;
14.1932 + top.sp[-1].i32 = 1;
14.1933 + break;
14.1934 +}
14.1935 +
14.1936 +case OP_FALSE:
14.1937 +{
14.1938 + top.sp++;
14.1939 + top.sp[-1].i32 = 0;
14.1940 + break;
14.1941 +}
14.1942 +
14.1943 +case OP_GETFIELD:
14.1944 +{
14.1945 + Struct *obj;
14.1946 + if (top.sp[-1].obj->is(MapKind_Module))
14.1947 + obj = Module::cast(top.sp[-1].obj)->globals();
14.1948 + else
14.1949 + obj = Struct::cast(top.sp[-1].obj);
14.1950 + GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
14.1951 + break;
14.1952 +}
14.1953 +
14.1954 +case OP_SETFIELD:
14.1955 +{
14.1956 + Struct *obj = Struct::cast(top.sp[-2].obj);
14.1957 + SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
14.1958 + top.sp[-2] = top.sp[-1];
14.1959 + top.sp--;
14.1960 + break;
14.1961 +}
14.1962 +
14.1963 +case OP_COPYSTRUCT:
14.1964 +{
14.1965 + Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
14.1966 + Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
14.1967 + if (!Struct::Copy(zone, left, right))
14.1968 + goto error;
14.1969 + top.sp[-2].obj = top.sp[-1].obj;
14.1970 + top.sp--;
14.1971 + break;
14.1972 +}
14.1973 +
14.1974 +case OP_TABLESWITCH:
14.1975 +{
14.1976 + int value = top.sp[-1].i32;
14.1977 + int low = READ_TABLESWITCH_LOW(top.pc);
14.1978 + int high = READ_TABLESWITCH_HIGH(top.pc);
14.1979 +
14.1980 + top.sp--;
14.1981 +
14.1982 + unsigned index = unsigned(value - low);
14.1983 + unsigned tablesize = TableSwitchEntries(low, high);
14.1984 + if (index < tablesize) {
14.1985 + top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
14.1986 + top.pc += index * OP_JUMP_LENGTH;
14.1987 + continue;
14.1988 + }
14.1989 + break;
14.1990 +}
14.1991 +
14.1992 +case OP_SIZEOF:
14.1993 +{
14.1994 + Array *array = Array::cast(top.sp[-1].obj);
14.1995 + top.sp[-1].i32 = array->length();
14.1996 + break;
14.1997 +}
14.1998 +
14.1999 +case OP_PUBLIC:
14.2000 +{
14.2001 + Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
14.2002 + zone->registerPublic(fun);
14.2003 + top.sp--;
14.2004 + break;
14.2005 +}
14.2006 +
14.2007 +case OP_SETGLOBAL:
14.2008 +{
14.2009 + Local<Code> code(zone, top.fp->code());
14.2010 + Local<Struct> obj(zone, code->module()->globals());
14.2011 + Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
14.2012 + SetGlobal(zone, obj, name, top.sp[-1]);
14.2013 + break;
14.2014 +}
14.2015 +
14.2016 +case OP_GETGLOBAL:
14.2017 +{
14.2018 + Local<Code> code(zone, top.fp->code());
14.2019 + Local<Struct> obj(zone, code->module()->globals());
14.2020 + Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
14.2021 + GetGlobal(zone, obj, name, top.sp);
14.2022 + top.sp++;
14.2023 + break;
14.2024 +}
14.2025 +
14.2026 +case OP_ENTERLOOP:
14.2027 +{
14.2028 + top.fp->enterLoop(zone);
14.2029 + break;
14.2030 +}
14.2031 +
14.2032 +case OP_LEAVELOOP:
14.2033 +{
14.2034 + top.fp->leaveLoop(zone);
14.2035 + break;
14.2036 +}
14.2037 +
14.2038 +case OP_DEPARRAY:
14.2039 +{
14.2040 + Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
14.2041 + Local<Array> array(zone, Array::cast(top.sp[-2].obj));
14.2042 + int index = top.sp[-1].i32;
14.2043 +
14.2044 + // We allow taking 0-length dependent arrays.
14.2045 + if (index < 0 || unsigned(index) > array->length()) {
14.2046 + zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
14.2047 + goto error;
14.2048 + }
14.2049 +
14.2050 + top.sp[-2].obj = DependentArray::New(zone, array, map, index);
14.2051 + if (!top.sp[-2].obj)
14.2052 + goto error;
14.2053 +
14.2054 + top.sp--;
14.2055 + break;
14.2056 +}
14.2057 +
14.2058 +case OP_IMPORT:
14.2059 +{
14.2060 + unsigned index = READ_UINT32(top.pc);
14.2061 +
14.2062 + top.sp++;
14.2063 + top.sp[-1].obj = top.fp->code()->module()->getImportAt(index);
14.2064 + break;
14.2065 +}
14.2066 +
14.2067 +default:
14.2068 + assert(false);
14.2069 + return false;
14.2070 +
14.2071 + }
14.2072 +
14.2073 + top.pc += OpcodeInfo[op].length;
14.2074 + assert(top.sp >= top.fp->stackBase());
14.2075 + }
14.2076 +
14.2077 +done:
14.2078 + return true;
14.2079 +
14.2080 +error:
14.2081 + // Unwind frames until we can continue.
14.2082 + while (top.fp != entryFrame)
14.2083 + zone->stack().popInlineFrame();
14.2084 + return false;
14.2085 +}
15.1 --- a/src/Interpreter.h Mon Jun 10 00:46:29 2013 +0100
15.2 +++ b/src/Interpreter.h Mon Jun 10 01:04:43 2013 +0100
15.3 @@ -1,29 +1,29 @@
15.4 -/*
15.5 - * Copyright (C) 2012 David Anderson
15.6 - *
15.7 - * This file is part of JITCraft.
15.8 - *
15.9 - * JITCraft is free software: you can redistribute it and/or modify it under
15.10 - * the terms of the GNU General Public License as published by the Free
15.11 - * Software Foundation, either version 3 of the License, or (at your option)
15.12 - * any later version.
15.13 - *
15.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
15.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15.17 - *
15.18 - * You should have received a copy of the GNU General Public License along with
15.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
15.20 - */
15.21 -#ifndef _include_jc_interpreter_h_
15.22 -#define _include_jc_interpreter_h_
15.23 -
15.24 -#include "Stack.h"
15.25 -
15.26 -namespace ke {
15.27 -
15.28 -bool Interpret(Zone *zone, Frame *frame, LocalSlot *result);
15.29 -
15.30 -}
15.31 -
15.32 -#endif // _include_jc_interpreter_h_
15.33 +/*
15.34 + * Copyright (C) 2012 David Anderson
15.35 + *
15.36 + * This file is part of JITCraft.
15.37 + *
15.38 + * JITCraft is free software: you can redistribute it and/or modify it under
15.39 + * the terms of the GNU General Public License as published by the Free
15.40 + * Software Foundation, either version 3 of the License, or (at your option)
15.41 + * any later version.
15.42 + *
15.43 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
15.44 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15.45 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15.46 + *
15.47 + * You should have received a copy of the GNU General Public License along with
15.48 + * JITCraft. If not, see http://www.gnu.org/licenses/.
15.49 + */
15.50 +#ifndef _include_jc_interpreter_h_
15.51 +#define _include_jc_interpreter_h_
15.52 +
15.53 +#include "Stack.h"
15.54 +
15.55 +namespace ke {
15.56 +
15.57 +bool Interpret(Zone *zone, Frame *frame, LocalSlot *result);
15.58 +
15.59 +}
15.60 +
15.61 +#endif // _include_jc_interpreter_h_
16.1 --- a/src/Messages.h Mon Jun 10 00:46:29 2013 +0100
16.2 +++ b/src/Messages.h Mon Jun 10 01:04:43 2013 +0100
16.3 @@ -1,48 +1,48 @@
16.4 -/*
16.5 - * Copyright (C) 2012 David Anderson
16.6 - *
16.7 - * This file is part of JITCraft.
16.8 - *
16.9 - * JITCraft is free software: you can redistribute it and/or modify it under
16.10 - * the terms of the GNU General Public License as published by the Free
16.11 - * Software Foundation, either version 3 of the License, or (at your option)
16.12 - * any later version.
16.13 - *
16.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
16.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16.17 - *
16.18 - * You should have received a copy of the GNU General Public License along with
16.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
16.20 - */
16.21 -#ifndef _include_jitcraft_messages_h_
16.22 -#define _include_jitcraft_messages_h_
16.23 -
16.24 -namespace ke {
16.25 -
16.26 -enum MessageType
16.27 -{
16.28 - MessageType_SyntaxError,
16.29 - MessageType_TypeError,
16.30 - MessageType_SystemError
16.31 -};
16.32 -
16.33 -enum Message
16.34 -{
16.35 -#define MSG(Name, Type, String) Message_##Name,
16.36 -# include "Messages.tbl"
16.37 -#undef MSG
16.38 - MessageType_Total
16.39 -};
16.40 -
16.41 -struct MessageInfo
16.42 -{
16.43 - MessageType type;
16.44 - const char *format;
16.45 -};
16.46 -
16.47 -extern const MessageInfo Messages[];
16.48 -
16.49 -}
16.50 -
16.51 -#endif // _include_jitcraft_messages_h_
16.52 +/*
16.53 + * Copyright (C) 2012 David Anderson
16.54 + *
16.55 + * This file is part of JITCraft.
16.56 + *
16.57 + * JITCraft is free software: you can redistribute it and/or modify it under
16.58 + * the terms of the GNU General Public License as published by the Free
16.59 + * Software Foundation, either version 3 of the License, or (at your option)
16.60 + * any later version.
16.61 + *
16.62 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
16.63 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16.64 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16.65 + *
16.66 + * You should have received a copy of the GNU General Public License along with
16.67 + * JITCraft. If not, see http://www.gnu.org/licenses/.
16.68 + */
16.69 +#ifndef _include_jitcraft_messages_h_
16.70 +#define _include_jitcraft_messages_h_
16.71 +
16.72 +namespace ke {
16.73 +
16.74 +enum MessageType
16.75 +{
16.76 + MessageType_SyntaxError,
16.77 + MessageType_TypeError,
16.78 + MessageType_SystemError
16.79 +};
16.80 +
16.81 +enum Message
16.82 +{
16.83 +#define MSG(Name, Type, String) Message_##Name,
16.84 +# include "Messages.tbl"
16.85 +#undef MSG
16.86 + MessageType_Total
16.87 +};
16.88 +
16.89 +struct MessageInfo
16.90 +{
16.91 + MessageType type;
16.92 + const char *format;
16.93 +};
16.94 +
16.95 +extern const MessageInfo Messages[];
16.96 +
16.97 +}
16.98 +
16.99 +#endif // _include_jitcraft_messages_h_
17.1 --- a/src/Modules.cpp Mon Jun 10 00:46:29 2013 +0100
17.2 +++ b/src/Modules.cpp Mon Jun 10 01:04:43 2013 +0100
17.3 @@ -1,40 +1,40 @@
17.4 -/*
17.5 - * Copyright (C) 2012 David Anderson
17.6 - *
17.7 - * This file is part of JITCraft.
17.8 - *
17.9 - * JITCraft is free software: you can redistribute it and/or modify it under
17.10 - * the terms of the GNU General Public License as published by the Free
17.11 - * Software Foundation, either version 3 of the License, or (at your option)
17.12 - * any later version.
17.13 - *
17.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
17.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17.17 - *
17.18 - * You should have received a copy of the GNU General Public License along with
17.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
17.20 - */
17.21 -#include "Modules.h"
17.22 -#include "Zone.h"
17.23 -#include "Heap.h"
17.24 -#include "Heap-inl.h"
17.25 -
17.26 -using namespace ke;
17.27 -
17.28 -Module *
17.29 -Module::New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name)
17.30 -{
17.31 - Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
17.32 - if (!module)
17.33 - return NULL;
17.34 -
17.35 - module->parent_ = package;
17.36 - module->path_ = path;
17.37 - module->name_ = name;
17.38 - module->globals_ = NULL;
17.39 - module->nativeIdentity_ = NULL;
17.40 - module->globals_ = NULL;
17.41 - module->unit_ = NULL;
17.42 - return module;
17.43 -}
17.44 +/*
17.45 + * Copyright (C) 2012 David Anderson
17.46 + *
17.47 + * This file is part of JITCraft.
17.48 + *
17.49 + * JITCraft is free software: you can redistribute it and/or modify it under
17.50 + * the terms of the GNU General Public License as published by the Free
17.51 + * Software Foundation, either version 3 of the License, or (at your option)
17.52 + * any later version.
17.53 + *
17.54 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
17.55 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17.56 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17.57 + *
17.58 + * You should have received a copy of the GNU General Public License along with
17.59 + * JITCraft. If not, see http://www.gnu.org/licenses/.
17.60 + */
17.61 +#include "Modules.h"
17.62 +#include "Zone.h"
17.63 +#include "Heap.h"
17.64 +#include "Heap-inl.h"
17.65 +
17.66 +using namespace ke;
17.67 +
17.68 +Module *
17.69 +Module::New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name)
17.70 +{
17.71 + Local<Module> module(zone, Module::cast(zone->allocate(MapKind_Module, sizeof(Module), Heap::Tenure_Old)));
17.72 + if (!module)
17.73 + return NULL;
17.74 +
17.75 + module->parent_ = package;
17.76 + module->path_ = path;
17.77 + module->name_ = name;
17.78 + module->globals_ = NULL;
17.79 + module->nativeIdentity_ = NULL;
17.80 + module->globals_ = NULL;
17.81 + module->unit_ = NULL;
17.82 + return module;
17.83 +}
18.1 --- a/src/Modules.h Mon Jun 10 00:46:29 2013 +0100
18.2 +++ b/src/Modules.h Mon Jun 10 01:04:43 2013 +0100
18.3 @@ -1,107 +1,107 @@
18.4 -/*
18.5 - * Copyright (C) 2012 David Anderson
18.6 - *
18.7 - * This file is part of SourcePawn.
18.8 - *
18.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
18.10 - * the terms of the GNU General Public License as published by the Free
18.11 - * Software Foundation, either version 3 of the License, or (at your option)
18.12 - * any later version.
18.13 - *
18.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
18.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18.17 - *
18.18 - * You should have received a copy of the GNU General Public License along with
18.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
18.20 - */
18.21 -#ifndef _include_jc_module_h_
18.22 -#define _include_jc_module_h_
18.23 -
18.24 -#include "Heap.h"
18.25 -#include "Code.h"
18.26 -#include "Functions.h"
18.27 -#include "FixedArray.h"
18.28 -#include "Packages.h"
18.29 -
18.30 -namespace ke {
18.31 -
18.32 -class Environment;
18.33 -class Struct;
18.34 -class Package;
18.35 -struct TranslationUnit;
18.36 -
18.37 -class Module : public Importable
18.38 -{
18.39 - Barriered<Code> code_;
18.40 - Barriered<Struct> globals_;
18.41 - void *nativeIdentity_;
18.42 - TranslationUnit *unit_;
18.43 - Barriered<FixedArray> imports_;
18.44 -
18.45 - public:
18.46 - static Module *New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name);
18.47 -
18.48 - Code *code() {
18.49 - return code_;
18.50 - }
18.51 - Struct *globals() {
18.52 - return globals_;
18.53 - }
18.54 -
18.55 - bool compiled() {
18.56 - return !!code_;
18.57 - }
18.58 -
18.59 - // Modules are pre-created, and may have their intermediate compilation
18.60 - // data attached while they are being compiled.
18.61 - bool compiling() {
18.62 - return !!unit_;
18.63 - }
18.64 - TranslationUnit *translationUnit() {
18.65 - return unit_;
18.66 - }
18.67 - void setTranslationUnit(TranslationUnit *unit) {
18.68 - unit_ = unit;
18.69 - }
18.70 -
18.71 - unsigned imports() {
18.72 - return imports_ ? imports_->length() / 2 : 0;
18.73 - }
18.74 - Importable *getImportAt(unsigned index) {
18.75 - return Importable::cast(imports_->at(index * 2));
18.76 - }
18.77 - FixedArray *importPathAt(unsigned index) {
18.78 - return FixedArray::cast(imports_->at(index * 2 + 1));
18.79 - }
18.80 - void setImports(Handle<FixedArray> imports) {
18.81 - imports_ = imports;
18.82 - }
18.83 - void setCode(Handle<Code> code) {
18.84 - code_ = code;
18.85 - }
18.86 - void setGlobals(Handle<Struct> globals) {
18.87 - globals_ = globals;
18.88 - }
18.89 -
18.90 - // Begin GC Descriptor.
18.91 - static inline size_t offsetOfCode() {
18.92 - return OFFSETOF(Module, code_);
18.93 - }
18.94 - static inline size_t offsetOfGlobals() {
18.95 - return OFFSETOF(Module, globals_);
18.96 - }
18.97 - static inline size_t offsetOfImports() {
18.98 - return OFFSETOF(Module, imports_);
18.99 - }
18.100 - // End GC Descriptor.
18.101 -
18.102 - static inline Module *cast(Object *obj) {
18.103 - assert(!obj || obj->is(MapKind_Module));
18.104 - return reinterpret_cast<Module *>(obj);
18.105 - }
18.106 -};
18.107 -
18.108 -}
18.109 -
18.110 -#endif // _include_jc_module_h_
18.111 +/*
18.112 + * Copyright (C) 2012 David Anderson
18.113 + *
18.114 + * This file is part of SourcePawn.
18.115 + *
18.116 + * SourcePawn is free software: you can redistribute it and/or modify it under
18.117 + * the terms of the GNU General Public License as published by the Free
18.118 + * Software Foundation, either version 3 of the License, or (at your option)
18.119 + * any later version.
18.120 + *
18.121 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
18.122 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18.123 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18.124 + *
18.125 + * You should have received a copy of the GNU General Public License along with
18.126 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
18.127 + */
18.128 +#ifndef _include_jc_module_h_
18.129 +#define _include_jc_module_h_
18.130 +
18.131 +#include "Heap.h"
18.132 +#include "Code.h"
18.133 +#include "Functions.h"
18.134 +#include "FixedArray.h"
18.135 +#include "Packages.h"
18.136 +
18.137 +namespace ke {
18.138 +
18.139 +class Environment;
18.140 +class Struct;
18.141 +class Package;
18.142 +struct TranslationUnit;
18.143 +
18.144 +class Module : public Importable
18.145 +{
18.146 + Barriered<Code> code_;
18.147 + Barriered<Struct> globals_;
18.148 + void *nativeIdentity_;
18.149 + TranslationUnit *unit_;
18.150 + Barriered<FixedArray> imports_;
18.151 +
18.152 + public:
18.153 + static Module *New(Zone *zone, Handle<Package> package, Handle<String> path, Handle<String> name);
18.154 +
18.155 + Code *code() {
18.156 + return code_;
18.157 + }
18.158 + Struct *globals() {
18.159 + return globals_;
18.160 + }
18.161 +
18.162 + bool compiled() {
18.163 + return !!code_;
18.164 + }
18.165 +
18.166 + // Modules are pre-created, and may have their intermediate compilation
18.167 + // data attached while they are being compiled.
18.168 + bool compiling() {
18.169 + return !!unit_;
18.170 + }
18.171 + TranslationUnit *translationUnit() {
18.172 + return unit_;
18.173 + }
18.174 + void setTranslationUnit(TranslationUnit *unit) {
18.175 + unit_ = unit;
18.176 + }
18.177 +
18.178 + unsigned imports() {
18.179 + return imports_ ? imports_->length() / 2 : 0;
18.180 + }
18.181 + Importable *getImportAt(unsigned index) {
18.182 + return Importable::cast(imports_->at(index * 2));
18.183 + }
18.184 + FixedArray *importPathAt(unsigned index) {
18.185 + return FixedArray::cast(imports_->at(index * 2 + 1));
18.186 + }
18.187 + void setImports(Handle<FixedArray> imports) {
18.188 + imports_ = imports;
18.189 + }
18.190 + void setCode(Handle<Code> code) {
18.191 + code_ = code;
18.192 + }
18.193 + void setGlobals(Handle<Struct> globals) {
18.194 + globals_ = globals;
18.195 + }
18.196 +
18.197 + // Begin GC Descriptor.
18.198 + static inline size_t offsetOfCode() {
18.199 + return OFFSETOF(Module, code_);
18.200 + }
18.201 + static inline size_t offsetOfGlobals() {
18.202 + return OFFSETOF(Module, globals_);
18.203 + }
18.204 + static inline size_t offsetOfImports() {
18.205 + return OFFSETOF(Module, imports_);
18.206 + }
18.207 + // End GC Descriptor.
18.208 +
18.209 + static inline Module *cast(Object *obj) {
18.210 + assert(!obj || obj->is(MapKind_Module));
18.211 + return reinterpret_cast<Module *>(obj);
18.212 + }
18.213 +};
18.214 +
18.215 +}
18.216 +
18.217 +#endif // _include_jc_module_h_
19.1 --- a/src/NativeTable.cpp Mon Jun 10 00:46:29 2013 +0100
19.2 +++ b/src/NativeTable.cpp Mon Jun 10 01:04:43 2013 +0100
19.3 @@ -1,97 +1,97 @@
19.4 -/* vim: set ts=4 sw=4 tw=99 et:
19.5 - *
19.6 - * Copyright (C) 2012 David Anderson
19.7 - *
19.8 - * This file is part of SourcePawn.
19.9 - *
19.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
19.11 - * the terms of the GNU General Public License as published by the Free
19.12 - * Software Foundation, either version 3 of the License, or (at your option)
19.13 - * any later version.
19.14 - *
19.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
19.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19.18 - *
19.19 - * You should have received a copy of the GNU General Public License along with
19.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
19.21 - */
19.22 -#include "Zone.h"
19.23 -#include "NativeTable.h"
19.24 -#include "StringPool.h"
19.25 -#include "Heap-inl.h"
19.26 -
19.27 -using namespace ke;
19.28 -
19.29 -NativeTable::NativeTable(Zone *zone)
19.30 - : zone_(zone),
19.31 - nativeMap_(ZoneAllocatorPolicy())
19.32 -{
19.33 -}
19.34 -
19.35 -NativeTable::~NativeTable()
19.36 -{
19.37 - for (size_t i = 0; i < natives_.length(); i++)
19.38 - delete natives_[i];
19.39 -}
19.40 -
19.41 -bool
19.42 -NativeTable::initialize()
19.43 -{
19.44 - return nativeMap_.init(16);
19.45 -}
19.46 -
19.47 -bool
19.48 -NativeTable::add(Handle<String> name, size_t *indexp)
19.49 -{
19.50 - // :TODO: assert no GC
19.51 - CharsAndLength key(name->chars(), name->length());
19.52 - NativeMap::Insert p = nativeMap_.findForAdd(key);
19.53 - if (p.found()) {
19.54 - *indexp = (*p)->index;
19.55 - return true;
19.56 - }
19.57 -
19.58 - NativeInfo *info = new NativeInfo(name, NULL, natives_.length());
19.59 - if (!info || !natives_.append(info))
19.60 - return false;
19.61 -
19.62 - if (!nativeMap_.add(p, info))
19.63 - return false;
19.64 -
19.65 - *indexp = info->index;
19.66 -
19.67 - return true;
19.68 -}
19.69 -
19.70 -bool
19.71 -NativeTable::bind(const char *name, void *address)
19.72 -{
19.73 - CharsAndLength key(name, strlen(name));
19.74 - NativeMap::Insert p = nativeMap_.findForAdd(key);
19.75 - if (p.found()) {
19.76 - (*p)->address = address;
19.77 - return true;
19.78 - }
19.79 -
19.80 - Local<String> str(zone_, zone_->symbols()->add(key.str(), key.length()));
19.81 - if (!str)
19.82 - return false;
19.83 -
19.84 - // :TODO: assert no GC
19.85 - NativeInfo *info = new NativeInfo(str, address, natives_.length());
19.86 - if (!info || !natives_.append(info))
19.87 - return false;
19.88 -
19.89 - if (!nativeMap_.add(p, info))
19.90 - return false;
19.91 -
19.92 - return true;
19.93 -}
19.94 -
19.95 -void
19.96 -NativeTable::accept(VirtualObjectVisitor *visitor)
19.97 -{
19.98 - for (size_t i = 0; i < natives_.length(); i++)
19.99 - visitor->visit(natives_[i]->name.address());
19.100 -}
19.101 +/* vim: set ts=4 sw=4 tw=99 et:
19.102 + *
19.103 + * Copyright (C) 2012 David Anderson
19.104 + *
19.105 + * This file is part of SourcePawn.
19.106 + *
19.107 + * SourcePawn is free software: you can redistribute it and/or modify it under
19.108 + * the terms of the GNU General Public License as published by the Free
19.109 + * Software Foundation, either version 3 of the License, or (at your option)
19.110 + * any later version.
19.111 + *
19.112 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
19.113 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19.114 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19.115 + *
19.116 + * You should have received a copy of the GNU General Public License along with
19.117 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
19.118 + */
19.119 +#include "Zone.h"
19.120 +#include "NativeTable.h"
19.121 +#include "StringPool.h"
19.122 +#include "Heap-inl.h"
19.123 +
19.124 +using namespace ke;
19.125 +
19.126 +NativeTable::NativeTable(Zone *zone)
19.127 + : zone_(zone),
19.128 + nativeMap_(ZoneAllocatorPolicy())
19.129 +{
19.130 +}
19.131 +
19.132 +NativeTable::~NativeTable()
19.133 +{
19.134 + for (size_t i = 0; i < natives_.length(); i++)
19.135 + delete natives_[i];
19.136 +}
19.137 +
19.138 +bool
19.139 +NativeTable::initialize()
19.140 +{
19.141 + return nativeMap_.init(16);
19.142 +}
19.143 +
19.144 +bool
19.145 +NativeTable::add(Handle<String> name, size_t *indexp)
19.146 +{
19.147 + // :TODO: assert no GC
19.148 + CharsAndLength key(name->chars(), name->length());
19.149 + NativeMap::Insert p = nativeMap_.findForAdd(key);
19.150 + if (p.found()) {
19.151 + *indexp = (*p)->index;
19.152 + return true;
19.153 + }
19.154 +
19.155 + NativeInfo *info = new NativeInfo(name, NULL, natives_.length());
19.156 + if (!info || !natives_.append(info))
19.157 + return false;
19.158 +
19.159 + if (!nativeMap_.add(p, info))
19.160 + return false;
19.161 +
19.162 + *indexp = info->index;
19.163 +
19.164 + return true;
19.165 +}
19.166 +
19.167 +bool
19.168 +NativeTable::bind(const char *name, void *address)
19.169 +{
19.170 + CharsAndLength key(name, strlen(name));
19.171 + NativeMap::Insert p = nativeMap_.findForAdd(key);
19.172 + if (p.found()) {
19.173 + (*p)->address = address;
19.174 + return true;
19.175 + }
19.176 +
19.177 + Local<String> str(zone_, zone_->symbols()->add(key.str(), key.length()));
19.178 + if (!str)
19.179 + return false;
19.180 +
19.181 + // :TODO: assert no GC
19.182 + NativeInfo *info = new NativeInfo(str, address, natives_.length());
19.183 + if (!info || !natives_.append(info))
19.184 + return false;
19.185 +
19.186 + if (!nativeMap_.add(p, info))
19.187 + return false;
19.188 +
19.189 + return true;
19.190 +}
19.191 +
19.192 +void
19.193 +NativeTable::accept(VirtualObjectVisitor *visitor)
19.194 +{
19.195 + for (size_t i = 0; i < natives_.length(); i++)
19.196 + visitor->visit(natives_[i]->name.address());
19.197 +}
20.1 --- a/src/NativeTable.h Mon Jun 10 00:46:29 2013 +0100
20.2 +++ b/src/NativeTable.h Mon Jun 10 01:04:43 2013 +0100
20.3 @@ -1,90 +1,90 @@
20.4 -/* vim: set ts=4 sw=4 tw=99 et:
20.5 - *
20.6 - * Copyright (C) 2012 David Anderson
20.7 - *
20.8 - * This file is part of SourcePawn.
20.9 - *
20.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
20.11 - * the terms of the GNU General Public License as published by the Free
20.12 - * Software Foundation, either version 3 of the License, or (at your option)
20.13 - * any later version.
20.14 - *
20.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
20.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20.18 - *
20.19 - * You should have received a copy of the GNU General Public License along with
20.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
20.21 - */
20.22 -#ifndef _include_sp2_native_table_h_
20.23 -#define _include_sp2_native_table_h_
20.24 -
20.25 -#include <string.h>
20.26 -#include "AllocatorPolicies.h"
20.27 -#include "Strings.h"
20.28 -#include "HashTable.h"
20.29 -#include "Vector.h"
20.30 -#include "VirtualObjectVisitor.h"
20.31 -
20.32 -namespace ke {
20.33 -
20.34 -class NativeTable
20.35 -{
20.36 - public:
20.37 - NativeTable(Zone *zone);
20.38 - ~NativeTable();
20.39 -
20.40 - private:
20.41 - struct NativeInfo {
20.42 - Unbarriered<String> name;
20.43 - void *address;
20.44 - size_t index;
20.45 -
20.46 - NativeInfo(String *name, void *address, size_t index)
20.47 - : address(address),
20.48 - index(index)
20.49 - {
20.50 - this->name = name;
20.51 - }
20.52 - };
20.53 -
20.54 - struct Policy
20.55 - {
20.56 - typedef NativeInfo * Payload;
20.57 -
20.58 - static uint32 hash(const CharsAndLength &key) {
20.59 - return HashCharSequence(key.str(), key.length());
20.60 - }
20.61 -
20.62 - static bool matches(const CharsAndLength &key, NativeInfo *info) {
20.63 - if (info->name->length() != key.length())
20.64 - return false;
20.65 - return memcmp(info->name->chars(), key.str(), key.length() * sizeof(char)) == 0;
20.66 - }
20.67 - };
20.68 -
20.69 - typedef HashTable<Policy, ZoneAllocatorPolicy> NativeMap;
20.70 -
20.71 - public:
20.72 - bool initialize();
20.73 -
20.74 - bool bind(const char *name, void *address);
20.75 - bool add(Handle<String> name, size_t *indexp);
20.76 - String *name(size_t index) const {
20.77 - return natives_[index]->name;
20.78 - }
20.79 - void *address(size_t index) const {
20.80 - return natives_[index]->address;
20.81 - }
20.82 -
20.83 - void accept(VirtualObjectVisitor *visitor);
20.84 -
20.85 - private:
20.86 - Zone *zone_;
20.87 - NativeMap nativeMap_;
20.88 - Vector<NativeInfo *> natives_;
20.89 -};
20.90 -
20.91 -}
20.92 -
20.93 -#endif // _include_sp2_native_table_h_
20.94 +/* vim: set ts=4 sw=4 tw=99 et:
20.95 + *
20.96 + * Copyright (C) 2012 David Anderson
20.97 + *
20.98 + * This file is part of SourcePawn.
20.99 + *
20.100 + * SourcePawn is free software: you can redistribute it and/or modify it under
20.101 + * the terms of the GNU General Public License as published by the Free
20.102 + * Software Foundation, either version 3 of the License, or (at your option)
20.103 + * any later version.
20.104 + *
20.105 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
20.106 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20.107 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20.108 + *
20.109 + * You should have received a copy of the GNU General Public License along with
20.110 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
20.111 + */
20.112 +#ifndef _include_sp2_native_table_h_
20.113 +#define _include_sp2_native_table_h_
20.114 +
20.115 +#include <string.h>
20.116 +#include "AllocatorPolicies.h"
20.117 +#include "Strings.h"
20.118 +#include "HashTable.h"
20.119 +#include "Vector.h"
20.120 +#include "VirtualObjectVisitor.h"
20.121 +
20.122 +namespace ke {
20.123 +
20.124 +class NativeTable
20.125 +{
20.126 + public:
20.127 + NativeTable(Zone *zone);
20.128 + ~NativeTable();
20.129 +
20.130 + private:
20.131 + struct NativeInfo {
20.132 + Unbarriered<String> name;
20.133 + void *address;
20.134 + size_t index;
20.135 +
20.136 + NativeInfo(String *name, void *address, size_t index)
20.137 + : address(address),
20.138 + index(index)
20.139 + {
20.140 + this->name = name;
20.141 + }
20.142 + };
20.143 +
20.144 + struct Policy
20.145 + {
20.146 + typedef NativeInfo * Payload;
20.147 +
20.148 + static uint32 hash(const CharsAndLength &key) {
20.149 + return HashCharSequence(key.str(), key.length());
20.150 + }
20.151 +
20.152 + static bool matches(const CharsAndLength &key, NativeInfo *info) {
20.153 + if (info->name->length() != key.length())
20.154 + return false;
20.155 + return memcmp(info->name->chars(), key.str(), key.length() * sizeof(char)) == 0;
20.156 + }
20.157 + };
20.158 +
20.159 + typedef HashTable<Policy, ZoneAllocatorPolicy> NativeMap;
20.160 +
20.161 + public:
20.162 + bool initialize();
20.163 +
20.164 + bool bind(const char *name, void *address);
20.165 + bool add(Handle<String> name, size_t *indexp);
20.166 + String *name(size_t index) const {
20.167 + return natives_[index]->name;
20.168 + }
20.169 + void *address(size_t index) const {
20.170 + return natives_[index]->address;
20.171 + }
20.172 +
20.173 + void accept(VirtualObjectVisitor *visitor);
20.174 +
20.175 + private:
20.176 + Zone *zone_;
20.177 + NativeMap nativeMap_;
20.178 + Vector<NativeInfo *> natives_;
20.179 +};
20.180 +
20.181 +}
20.182 +
20.183 +#endif // _include_sp2_native_table_h_
21.1 --- a/src/OldByCo.cpp Mon Jun 10 00:46:29 2013 +0100
21.2 +++ b/src/OldByCo.cpp Mon Jun 10 01:04:43 2013 +0100
21.3 @@ -1,1585 +1,1585 @@
21.4 -/* vim: set ts=4 sw=4 tw=99 et:
21.5 - *
21.6 - * Copyright (C) 2012 David Anderson
21.7 - *
21.8 - * This file is part of JITCraft.
21.9 - *
21.10 - * JITCraft is free software: you can redistribute it and/or modify it under
21.11 - * the terms of the GNU General Public License as published by the Free
21.12 - * Software Foundation, either version 3 of the License, or (at your option)
21.13 - * any later version.
21.14 - *
21.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
21.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21.18 - *
21.19 - * You should have received a copy of the GNU General Public License along with
21.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
21.21 - */
21.22 -#include <string.h>
21.23 -#include "../Modules.h"
21.24 -#include "../Types.h"
21.25 -#include "../Array.h"
21.26 -#include "../Strings.h"
21.27 -#include "../Zone.h"
21.28 -#include "../Environments.h"
21.29 -#include "../Box.h"
21.30 -#include "../Heap-inl.h"
21.31 -#include "BytecodeCompiler.h"
21.32 -#include "Scopes.h"
21.33 -
21.34 -using namespace ke;
21.35 -
21.36 -typedef BytecodeEmitter::Label Label;
21.37 -
21.38 -#define __ emitter_.
21.39 -
21.40 -BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
21.41 - : zone_(zone),
21.42 - tree_(tree),
21.43 - emitter_(zone->pool()),
21.44 - locals_(NULL),
21.45 - scope_(NULL),
21.46 - moduleData_(module),
21.47 - loop_(NULL)
21.48 -{
21.49 -}
21.50 -
21.51 -static inline TokenKind
21.52 -ToCompare(Expression *expr)
21.53 -{
21.54 - if (expr->isBinaryExpression()) {
21.55 - BinaryExpression *b = expr->toBinaryExpression();
21.56 - if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
21.57 - return b->token();
21.58 - } else if (expr->isUnaryExpression()) {
21.59 - UnaryExpression *u = expr->toUnaryExpression();
21.60 - if (u->token() == TOK_NOT)
21.61 - return TOK_NOT;
21.62 - }
21.63 - return TOK_EOF;
21.64 -}
21.65 -
21.66 -static inline Opcode
21.67 -CompareTokenToJump(TokenKind kind)
21.68 -{
21.69 - switch (kind) {
21.70 - case TOK_EQUALS:
21.71 - return OP_JEQ;
21.72 - case TOK_NOTEQUALS:
21.73 - return OP_JNE;
21.74 - case TOK_GT:
21.75 - return OP_JG;
21.76 - case TOK_GE:
21.77 - return OP_JGE;
21.78 - case TOK_LT:
21.79 - return OP_JL;
21.80 - default:
21.81 - assert(kind == TOK_LE);
21.82 - return OP_JLE;
21.83 - }
21.84 -}
21.85 -
21.86 -static inline Opcode
21.87 -TokenToOpcode(TokenKind kind)
21.88 -{
21.89 - switch (kind) {
21.90 - case TOK_PLUS:
21.91 - return OP_ADD;
21.92 - case TOK_MINUS:
21.93 - return OP_SUB;
21.94 - case TOK_STAR:
21.95 - return OP_MUL;
21.96 - case TOK_SLASH:
21.97 - return OP_DIV;
21.98 - case TOK_PERCENT:
21.99 - return OP_MOD;
21.100 - case TOK_SHR:
21.101 - return OP_SHR;
21.102 - case TOK_USHR:
21.103 - return OP_USHR;
21.104 - case TOK_SHL:
21.105 - return OP_SHL;
21.106 - case TOK_BITAND:
21.107 - return OP_BITAND;
21.108 - case TOK_BITOR:
21.109 - return OP_BITOR;
21.110 - case TOK_GT:
21.111 - return OP_GT;
21.112 - case TOK_GE:
21.113 - return OP_GE;
21.114 - case TOK_LT:
21.115 - return OP_LT;
21.116 - case TOK_LE:
21.117 - return OP_LE;
21.118 - case TOK_EQUALS:
21.119 - return OP_EQ;
21.120 - case TOK_NOTEQUALS:
21.121 - return OP_NE;
21.122 - default:
21.123 - assert(kind == TOK_BITXOR);
21.124 - return OP_BITXOR;
21.125 - }
21.126 -}
21.127 -
21.128 -void
21.129 -BytecodeCompiler::recordLifoSlot(Scope *scope)
21.130 -{
21.131 - if (!scope)
21.132 - return;
21.133 -
21.134 - if (Variable *var = scope->lifoSlot()) {
21.135 - locals_->set(zone_, var->slot(), var->type());
21.136 - __ savelifo(var->slot());
21.137 - }
21.138 -}
21.139 -
21.140 -void
21.141 -BytecodeCompiler::unwindTo(Scope *scope)
21.142 -{
21.143 - // Note: we only need to unwind to the outermost scope's LIFO slot.
21.144 - Variable *var = NULL;
21.145 - for (Scope *current = scope_; current != scope; current = current->enclosing()) {
21.146 - if (Variable *slot = current->lifoSlot())
21.147 - var = slot;
21.148 - }
21.149 -
21.150 - if (var)
21.151 - __ unwindlifo(var->slot());
21.152 -}
21.153 -
21.154 -void
21.155 -BytecodeCompiler::visit(NameProxy *name)
21.156 -{
21.157 - switch (name->binding()->kind()) {
21.158 - case BoundName::VARIABLE:
21.159 - {
21.160 - Variable *var = name->binding()->toVariable();
21.161 -
21.162 - if (var->location() == Variable::STACK) {
21.163 - __ getlocal(var);
21.164 - assert(!name->type()->isReference());
21.165 - } else if (var->location() == Variable::ENVIRONMENT) {
21.166 - getEnvSlot(var);
21.167 - } else {
21.168 - assert(var->location() == Variable::PARAMETER);
21.169 - __ getarg(var);
21.170 -
21.171 - // If this argument is actually a reference, dereference it now.
21.172 - if (var->type()->isReference())
21.173 - __ getref(var->type()->contained());
21.174 - }
21.175 - break;
21.176 - }
21.177 -
21.178 - case BoundName::FUNCTION:
21.179 - {
21.180 - NamedFunction *fun = name->binding()->toNamedFunction();
21.181 - __ module();
21.182 - __ getmodule_fn(fun->slot());
21.183 - break;
21.184 - }
21.185 -
21.186 - default:
21.187 - {
21.188 - NamedConstant *constant = name->binding()->toNamedConstant();
21.189 - __ int_(constant->value().toInt());
21.190 - break;
21.191 - }
21.192 - }
21.193 -}
21.194 -
21.195 -void
21.196 -BytecodeCompiler::visit(ExpressionStatement *node)
21.197 -{
21.198 - // Expressions leave their value on the top of the stack, so we make sure
21.199 - // to balance the stack if they're used as a statement.
21.200 - node->expression()->accept(this);
21.201 - if (!node->expression()->type()->isVoid())
21.202 - __ pop();
21.203 -}
21.204 -
21.205 -static inline bool
21.206 -IsCompositeValueType(Type *type)
21.207 -{
21.208 - return type->isStruct() ||
21.209 - (type->isArray() && type->isFixedLength());
21.210 -}
21.211 -
21.212 -static inline Array *
21.213 -StringLiteralToArray(Zone *zone, StringLiteral *node)
21.214 -{
21.215 - Local<Type> type(zone, node->type());
21.216 - Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
21.217 - if (!map)
21.218 - return NULL;
21.219 -
21.220 - return Array::NewString(zone,
21.221 - map,
21.222 - node->string()->raw(),
21.223 - node->string()->length(),
21.224 - Heap::Tenure_Old);
21.225 -}
21.226 -
21.227 -void
21.228 -BytecodeCompiler::visit(Assignment *node)
21.229 -{
21.230 - Local<Type> left(zone_, node->type());
21.231 - Local<Type> right(zone_, node->expression()->type());
21.232 -
21.233 - // The first step is three sub-steps:
21.234 - //
21.235 - // (1) Bind the left-hand side.
21.236 - // -- If a cumulative operation (+=, etc):
21.237 - // (2) Save a copy of the binding on the stack.
21.238 - // (3) Dereference the binding to get a value.
21.239 - //
21.240 - if (node->lvalue()->isNameProxy()) {
21.241 - NameProxy *proxy = node->lvalue()->toNameProxy();
21.242 - Variable *var = proxy->binding()->toVariable();
21.243 -
21.244 - // We need to fetch the variable under the following circumstances:
21.245 - // (1) The variable is a reference, since we'll store into the ref.
21.246 - // (2) The variable is a fixed array, since we need to copy into it.
21.247 - // (3) The variable is a struct, since we need to copy into it.
21.248 - if (var->type()->isReference() || IsCompositeValueType(var->type()))
21.249 - __ get(var);
21.250 -
21.251 - // Get the value if needed.
21.252 - if (node->token() != TOK_ASSIGN) {
21.253 - // += etc is not allowed on arrays.
21.254 - assert(!var->type()->isArray());
21.255 -
21.256 - if (var->location() == Variable::ENVIRONMENT)
21.257 - getEnvSlot(var);
21.258 -
21.259 - if (var->type()->isReference()) {
21.260 - __ dup();
21.261 - __ getref(var->type()->contained());
21.262 - } else if (var->location() != Variable::ENVIRONMENT) {
21.263 - __ get(var);
21.264 - }
21.265 - }
21.266 - } else if (node->lvalue()->isFieldExpression()) {
21.267 - FieldExpression *expr = node->lvalue()->toFieldExpression();
21.268 - __ note_position(expr->pos());
21.269 -
21.270 - expr->left()->accept(this);
21.271 -
21.272 - if (node->token() != TOK_ASSIGN)
21.273 - __ dup();
21.274 -
21.275 - if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
21.276 - __ getfield(expr->fieldIndex(), left);
21.277 - } else {
21.278 - IndexExpression *index = node->lvalue()->toIndexExpression();
21.279 - __ note_position(index->pos());
21.280 -
21.281 - index->left()->accept(this);
21.282 - index->right()->accept(this);
21.283 -
21.284 - if (node->token() != TOK_ASSIGN)
21.285 - __ dup2();
21.286 -
21.287 - if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
21.288 - __ getelem(left);
21.289 - }
21.290 -
21.291 - if (node->token() == TOK_ASSIGN) {
21.292 - // Special case: if the left-hand side is a string literal, we must
21.293 - // spawn a new copy (:TODO: something about const?)
21.294 - if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
21.295 - Local<Array> string(zone_,
21.296 - StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
21.297 - if (!string)
21.298 - return;
21.299 -
21.300 - Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
21.301 - __ note_position(node->expression()->pos());
21.302 - __ int_(string->length());
21.303 - __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
21.304 - __ object(string);
21.305 - __ copyarray();
21.306 - } else {
21.307 - node->expression()->accept(this);
21.308 - }
21.309 - } else {
21.310 - visitForALU(left, node->expression());
21.311 -
21.312 - TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
21.313 - __ note_position(node->pos());
21.314 - __ binary(TokenToOpcode(alu));
21.315 - }
21.316 -
21.317 - // Emit the store.
21.318 - if (left->isArray() && left->isFixedLength()) {
21.319 - // (x = y) returns the left-hand side; if |x| is a fixed-length array,
21.320 - // then |y| is as well, and we perform a deep copy.
21.321 - assert(right->isFixedLength());
21.322 - __ note_position(node->pos());
21.323 - __ copyarray();
21.324 - } else if (left->isStruct()) {
21.325 - // Structs have value semantics, so emit a full copy. We don't break
21.326 - // this down into u-ops, to avoid unnecessary bytecode explosion.
21.327 - assert(right->isStruct());
21.328 - __ note_position(node->pos());
21.329 - __ copystruct();
21.330 - } else if (node->lvalue()->isNameProxy()) {
21.331 - NameProxy *proxy = node->lvalue()->toNameProxy();
21.332 - Variable *var = proxy->binding()->toVariable();
21.333 -
21.334 - if (var->type()->isReference())
21.335 - __ setref(var->type()->contained());
21.336 - else if (var->location() == Variable::ENVIRONMENT)
21.337 - setEnvSlot(var);
21.338 - else
21.339 - __ set(var);
21.340 - } else if (node->lvalue()->isFieldExpression()) {
21.341 - FieldExpression *expr = node->lvalue()->toFieldExpression();
21.342 - __ setfield(expr->fieldIndex(), left);
21.343 - } else {
21.344 - __ setelem(left);
21.345 - }
21.346 -}
21.347 -
21.348 -void
21.349 -BytecodeCompiler::visit(IncDecExpression *node)
21.350 -{
21.351 - // In the postfix case, the logic looks like:
21.352 - // (1) Bind -> REF
21.353 - // (2) Dup -> REF REF
21.354 - // (3) Fetch -> REF VAL
21.355 - // (4) Swap -> VAL REF
21.356 - // (5) Pick -> VAL REF VAL
21.357 - // (6) Add -> VAL REF VAL+1
21.358 - // (7) Store -> VAL VAL+1
21.359 - // (8) Drop -> VAL
21.360 - //
21.361 - // In the prefix case, the logic looks like:
21.362 - // (1) Bind -> REF
21.363 - // (2) Dup -> REF REF
21.364 - // (3) Fetch -> REF VAL
21.365 - // --
21.366 - // --
21.367 - // (6) Add -> REF VAL+1
21.368 - // (7) Store -> VAL+1
21.369 - // --
21.370 - //
21.371 - // This is squirrely enough such that we don't bother sharing too much
21.372 - // with the above.
21.373 - //
21.374 - // Note: We simulate a "Pick" operation with a dup2+pop.
21.375 -
21.376 - // This is steps (1) to (5).
21.377 - Expression *expr = node->expression();
21.378 - if (expr->isNameProxy()) {
21.379 - NameProxy *proxy = expr->toNameProxy();
21.380 - Variable *var = proxy->binding()->toVariable();
21.381 -
21.382 - // Bind.
21.383 - if (var->location() == Variable::ENVIRONMENT)
21.384 - getEnvSlot(var);
21.385 - else if (var->type()->isReference() || var->type()->isArray())
21.386 - __ get(var);
21.387 -
21.388 - // Dup and fetch.
21.389 - if (var->type()->isReference()) {
21.390 - __ dup();
21.391 - __ getref(node->type());
21.392 - if (node->postfix()) {
21.393 - __ swap();
21.394 - __ pick2();
21.395 - }
21.396 - } else {
21.397 - assert(!var->type()->isArray());
21.398 - if (var->location() != Variable::ENVIRONMENT)
21.399 - __ get(var);
21.400 - if (node->postfix())
21.401 - __ dup();
21.402 - }
21.403 - } else if (expr->isFieldExpression()) {
21.404 - FieldExpression *field = expr->toFieldExpression();
21.405 -
21.406 - field->left()->accept(this);
21.407 - __ dup();
21.408 - __ getfield(field->fieldIndex(), field->type());
21.409 -
21.410 - if (node->postfix()) {
21.411 - // The stack looks like this now:
21.412 - // OBJECT VALUE
21.413 - __ swap(); // VALUE OBJECT
21.414 - __ pick2(); // VALUE OBJECT VALUE
21.415 - }
21.416 - } else {
21.417 - IndexExpression *index = expr->toIndexExpression();
21.418 - __ note_position(index->pos());
21.419 -
21.420 - index->left()->accept(this);
21.421 - index->right()->accept(this);
21.422 -
21.423 - assert(!node->type()->isArray());
21.424 - __ dup2();
21.425 - __ getelem(node->type());
21.426 -
21.427 - if (node->postfix()) {
21.428 - // The stack looks like this now:
21.429 - // ARRAY INDEX VALUE
21.430 - //
21.431 - // So we must use a PICK operation to rotate the stack into position.
21.432 - __ roll3(); // INDEX VALUE ARRAY
21.433 - __ roll3(); // VALUE ARRAY INDEX
21.434 - __ pick3(); // VALUE ARRAY INDEX VALUE
21.435 - }
21.436 - }
21.437 -
21.438 - // Perform step (6).
21.439 - if (node->type()->isFloat()) {
21.440 - __ float_(1.0);
21.441 - } else {
21.442 - assert(node->type()->isInt32());
21.443 - __ int_(1);
21.444 - }
21.445 -
21.446 - __ note_position(node->pos());
21.447 - if (node->token() == TOK_INCREMENT)
21.448 - __ binary(OP_ADD);
21.449 - else
21.450 - __ binary(OP_SUB);
21.451 -
21.452 - // Perform step (7).
21.453 - if (expr->isNameProxy()) {
21.454 - NameProxy *proxy = expr->toNameProxy();
21.455 - Variable *var = proxy->binding()->toVariable();
21.456 -
21.457 - if (var->type()->isReference())
21.458 - __ setref(node->type());
21.459 - else if (var->location() == Variable::ENVIRONMENT)
21.460 - setEnvSlot(var);
21.461 - else
21.462 - __ set(var);
21.463 - } else if (expr->isFieldExpression()) {
21.464 - FieldExpression *field = expr->toFieldExpression();
21.465 - __ setfield(field->fieldIndex(), field->type());
21.466 - } else {
21.467 - assert(expr->isIndexExpression());
21.468 - __ setelem(node->type());
21.469 - }
21.470 -
21.471 - // Perform step (8).
21.472 - if (node->postfix())
21.473 - __ pop();
21.474 -}
21.475 -
21.476 -void
21.477 -BytecodeCompiler::visitForALU(Type *needed, Expression *node)
21.478 -{
21.479 - node->accept(this);
21.480 - if (needed->isFloat() && !node->type()->isFloat())
21.481 - __ cvt_i2f();
21.482 - else
21.483 - assert(needed->primitive() == node->type()->primitive());
21.484 -}
21.485 -
21.486 -static inline Type *
21.487 -GetCoercionType(TokenKind tok, Type *left, Type *right)
21.488 -{
21.489 - if (left->isFloat())
21.490 - return left;
21.491 - return right;
21.492 -}
21.493 -
21.494 -void
21.495 -BytecodeCompiler::visit(UnaryExpression *node)
21.496 -{
21.497 - Local<Type> out(zone_, ((Expression *)node)->type());
21.498 -
21.499 - switch (node->token()) {
21.500 - case TOK_MINUS:
21.501 - {
21.502 - Local<Type> type(zone_, node->expression()->type());
21.503 - node->expression()->accept(this);
21.504 -
21.505 - if (out->isFloat())
21.506 - __ neg_f();
21.507 - else
21.508 - __ neg();
21.509 - break;
21.510 - }
21.511 -
21.512 - case TOK_NOT:
21.513 - {
21.514 - Local<Type> type(zone_, node->expression()->type());
21.515 - node->expression()->accept(this);
21.516 -
21.517 - if (out->isFloat())
21.518 - __ not_f();
21.519 - else
21.520 - __ not_();
21.521 - break;
21.522 - }
21.523 -
21.524 - case TOK_LABEL:
21.525 - {
21.526 - Local<Type> from(zone_, node->expression()->type());
21.527 -
21.528 - node->expression()->accept(this);
21.529 - if (!from->isFloat() && out->isFloat())
21.530 - __ bits_f2i();
21.531 - else if (from->isFloat() && !out->isFloat())
21.532 - __ bits_i2f();
21.533 - break;
21.534 - }
21.535 -
21.536 - case TOK_SIZEOF:
21.537 - {
21.538 - Local<Type> type(zone_, node->expression()->type());
21.539 - if (type->isFixedLength()) {
21.540 - __ int_(type->fixedLength());
21.541 - } else {
21.542 - node->expression()->accept(this);
21.543 - __ sizeof_();
21.544 - }
21.545 - break;
21.546 - }
21.547 -
21.548 - default:
21.549 - assert(node->token() == TOK_TILDE);
21.550 - node->expression()->accept(this);
21.551 - __ bitnot();
21.552 - break;
21.553 - }
21.554 -}
21.555 -
21.556 -void
21.557 -BytecodeCompiler::visit(BinaryExpression *node)
21.558 -{
21.559 - if (node->token() == TOK_AND || node->token() == TOK_OR) {
21.560 - Label success, failure, done;
21.561 - visitForTest(node, &success, &failure, &success);
21.562 - __ bind(&success);
21.563 - __ int_(1);
21.564 - __ drop(1); // Otherwise, the stack depth will be +1 too much.
21.565 - __ jump(&done);
21.566 - __ bind(&failure);
21.567 - __ int_(0);
21.568 - __ bind(&done);
21.569 - return;
21.570 - }
21.571 -
21.572 - Local<Type> leftType(zone_, node->left()->type());
21.573 - Local<Type> rightType(zone_, node->right()->type());
21.574 - Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
21.575 -
21.576 - visitForALU(coerce, node->left());
21.577 - visitForALU(coerce, node->right());
21.578 -
21.579 - Opcode op = TokenToOpcode(node->token());
21.580 - if (node->type()->isFloat())
21.581 - op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
21.582 -
21.583 - __ note_position(node->pos());
21.584 - __ binary(op);
21.585 -}
21.586 -
21.587 -void
21.588 -BytecodeCompiler::visit(IndexExpression *node)
21.589 -{
21.590 - node->left()->accept(this);
21.591 - node->right()->accept(this);
21.592 - __ note_position(node->pos());
21.593 - __ getelem(node->type());
21.594 -}
21.595 -
21.596 -void
21.597 -BytecodeCompiler::visit(FieldExpression *node)
21.598 -{
21.599 - node->left()->accept(this);
21.600 - __ getfield(node->fieldIndex(), node->type());
21.601 -}
21.602 -
21.603 -void
21.604 -BytecodeCompiler::visit(ReturnStatement *node)
21.605 -{
21.606 - if (node->expression()) {
21.607 - node->expression()->accept(this);
21.608 - __ return_();
21.609 - } else {
21.610 - __ returnvoid();
21.611 - }
21.612 -}
21.613 -
21.614 -void
21.615 -BytecodeCompiler::visitForTest(Expression *expression,
21.616 - Label *trueBranch,
21.617 - Label *falseBranch,
21.618 - Label *fallthrough)
21.619 -{
21.620 - TokenKind token = ToCompare(expression);
21.621 - if (token == TOK_EOF || token == TOK_NOT) {
21.622 - if (token == TOK_EOF)
21.623 - expression->accept(this);
21.624 - else
21.625 - expression->toUnaryExpression()->expression()->accept(this);
21.626 -
21.627 - bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
21.628 -
21.629 - Opcode op = jumpOnTrue ? OP_JT : OP_JF;
21.630 - if (expression->type()->isFloat())
21.631 - op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
21.632 -
21.633 - if (fallthrough == falseBranch)
21.634 - __ j(op, trueBranch);
21.635 - else
21.636 - __ j(op, falseBranch);
21.637 - return;
21.638 - }
21.639 -
21.640 - BinaryExpression *binary = expression->toBinaryExpression();
21.641 -
21.642 - if (token == TOK_AND || token == TOK_OR) {
21.643 - Label next;
21.644 - if (token == TOK_AND)
21.645 - visitForTest(binary->left(), &next, falseBranch, &next);
21.646 - else
21.647 - visitForTest(binary->left(), trueBranch, &next, &next);
21.648 - __ bind(&next);
21.649 - visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
21.650 - return;
21.651 - }
21.652 -
21.653 - Opcode op = CompareTokenToJump(token);
21.654 - if (fallthrough == trueBranch)
21.655 - op = Invert(op);
21.656 -
21.657 - Local<Type> leftType(zone_, binary->left()->type());
21.658 - Local<Type> rightType(zone_, binary->right()->type());
21.659 - Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
21.660 -
21.661 - visitForALU(coerce, binary->left());
21.662 - visitForALU(coerce, binary->right());
21.663 - if (coerce->isFloat())
21.664 - op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
21.665 -
21.666 - if (fallthrough == trueBranch)
21.667 - __ j(op, falseBranch);
21.668 - else
21.669 - __ j(op, trueBranch);
21.670 -}
21.671 -
21.672 -void
21.673 -BytecodeCompiler::visit(ForStatement *node)
21.674 -{
21.675 - AutoEnterScope forScope(this, node->scope());
21.676 -
21.677 - recordLifoSlot(node->scope());
21.678 -
21.679 - Label join, update;
21.680 - LoopScope loop(scope_, &join, &update, &loop_);
21.681 -
21.682 - if (node->initialization())
21.683 - node->initialization()->accept(this);
21.684 -
21.685 - Label header, test;
21.686 - if (node->condition())
21.687 - __ jump(&test);
21.688 -
21.689 - __ bind(&header);
21.690 - node->body()->accept(this);
21.691 -
21.692 - __ bind(&update);
21.693 - if (node->update())
21.694 - node->update()->accept(this);
21.695 -
21.696 - if (node->condition()) {
21.697 - __ bind(&test);
21.698 - visitForTest(node->condition(), &header, &join, &join);
21.699 - } else {
21.700 - __ jump(&header);
21.701 - }
21.702 -
21.703 - __ bind(&join);
21.704 -
21.705 - if (node->scope())
21.706 - unwindTo(node->scope()->enclosing());
21.707 - assert(__ stackDepth() == 0);
21.708 -}
21.709 -
21.710 -void
21.711 -BytecodeCompiler::visit(WhileStatement *node)
21.712 -{
21.713 - Label header, join;
21.714 -
21.715 - __ bind(&header);
21.716 -
21.717 - LoopScope loop(scope_, &join, &header, &loop_);
21.718 -
21.719 - if (node->token() == TOK_WHILE) {
21.720 - Label body;
21.721 -
21.722 - visitForTest(node->condition(), &body, &join, &body);
21.723 - __ bind(&body);
21.724 - node->body()->accept(this);
21.725 - __ jump(&header);
21.726 - } else {
21.727 - node->body()->accept(this);
21.728 - visitForTest(node->condition(), &header, &join, &join);
21.729 - }
21.730 -
21.731 - __ bind(&join);
21.732 -}
21.733 -
21.734 -void
21.735 -BytecodeCompiler::visit(BreakStatement *node)
21.736 -{
21.737 - unwindTo(loop_->scope());
21.738 - __ jump(loop_->break_());
21.739 -}
21.740 -
21.741 -void
21.742 -BytecodeCompiler::visit(ContinueStatement *node)
21.743 -{
21.744 - unwindTo(loop_->scope());
21.745 - __ jump(loop_->continue_());
21.746 -}
21.747 -
21.748 -void
21.749 -BytecodeCompiler::visit(BlockStatement *node)
21.750 -{
21.751 - AutoEnterScope blockScope(this, node->scope());
21.752 -
21.753 - recordLifoSlot(node->scope());
21.754 -
21.755 - for (size_t i = 0; i < node->statements()->length(); i++) {
21.756 - Statement *statement = node->statements()->at(i);
21.757 - statement->accept(this);
21.758 - assert(__ stackDepth() == 0);
21.759 - }
21.760 -
21.761 - // We don't bother emitting an "unwind" instruction for function scopes,
21.762 - // since this is taken care of by the calling convention.
21.763 - if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
21.764 - unwindTo(node->scope()->enclosing());
21.765 -}
21.766 -
21.767 -void
21.768 -BytecodeCompiler::visit(IntegerLiteral *node)
21.769 -{
21.770 - __ int_(node->value());
21.771 -}
21.772 -
21.773 -void
21.774 -BytecodeCompiler::visit(BooleanLiteral *node)
21.775 -{
21.776 - if (node->token() == TOK_TRUE)
21.777 - __ true_();
21.778 - else
21.779 - __ false_();
21.780 -}
21.781 -
21.782 -void
21.783 -BytecodeCompiler::visit(FloatLiteral *node)
21.784 -{
21.785 - __ float_((float)node->value());
21.786 -}
21.787 -
21.788 -void
21.789 -BytecodeCompiler::visit(StringLiteral *node)
21.790 -{
21.791 - Local<Array> array(zone_, StringLiteralToArray(zone_, node));
21.792 - if (!array)
21.793 - return;
21.794 -
21.795 - __ note_position(node->pos());
21.796 - __ object(array);
21.797 -}
21.798 -
21.799 -void
21.800 -BytecodeCompiler::getEnvSlot(Variable *var)
21.801 -{
21.802 - assert(var->scope()->kind() == Scope::GLOBAL);
21.803 - __ getglobal(var);
21.804 -}
21.805 -
21.806 -void
21.807 -BytecodeCompiler::setEnvSlot(Variable *var)
21.808 -{
21.809 - assert(var->scope()->kind() == Scope::GLOBAL);
21.810 - __ setglobal(var);
21.811 -}
21.812 -
21.813 -static bool
21.814 -FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
21.815 -{
21.816 - Local<Array> string(zone);
21.817 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
21.818 - Expression *expr = literal->expressions()->at(i);
21.819 - StringLiteral *lit = expr->toStringLiteral();
21.820 - if ((string = StringLiteralToArray(zone, lit)) == NULL)
21.821 - return false;
21.822 -
21.823 - array->writeObject(zone, i, string);
21.824 -
21.825 - if (string->length() > *maxsize)
21.826 - *maxsize = string->length();
21.827 -
21.828 - assert(!array->type()->contained()->isFixedLength() ||
21.829 - array->type()->contained()->fixedLength() >= string->length());
21.830 - }
21.831 -
21.832 - return true;
21.833 -}
21.834 -
21.835 -static bool
21.836 -FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
21.837 -{
21.838 - assert(array->type()->fixedLength() == literal->expressions()->length());
21.839 -
21.840 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
21.841 - Expression *expr = literal->expressions()->at(i);
21.842 - if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
21.843 - array->writeInt32(i, lit->value());
21.844 - continue;
21.845 - }
21.846 - if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
21.847 - if (lit->token() == TOK_TRUE)
21.848 - array->writeInt32(i, 1);
21.849 - else
21.850 - array->writeInt32(i, 0);
21.851 - continue;
21.852 - }
21.853 - if (FloatLiteral *lit = expr->asFloatLiteral()) {
21.854 - array->writeFloat(i, (float)lit->value());
21.855 - continue;
21.856 - }
21.857 -
21.858 - // Unrecognized literal type.
21.859 - assert(false);
21.860 - }
21.861 -
21.862 - return true;
21.863 -}
21.864 -
21.865 -static bool
21.866 -TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
21.867 - unsigned *maxsize)
21.868 -{
21.869 - assert(type->fixedLength() == literal->expressions()->length());
21.870 -
21.871 - Local<Type> contained(zone, type->contained());
21.872 - if (contained->isCharArray())
21.873 - return FillArrayLiteral_String(zone, array, literal, maxsize);
21.874 -
21.875 - if (!contained->isArray())
21.876 - return FillArrayLiteral_Primitive(zone, array, literal);
21.877 -
21.878 - Local<Array> subarray(zone);
21.879 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
21.880 - Expression *expr = literal->expressions()->at(i);
21.881 - subarray = Array::cast(array->readObject(i));
21.882 - if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
21.883 - return false;
21.884 - }
21.885 -
21.886 - return true;
21.887 -}
21.888 -
21.889 -static Array *
21.890 -BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
21.891 -{
21.892 - Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
21.893 - if (!root)
21.894 - return NULL;
21.895 -
21.896 - // This should have allocated everything in the array, so all we need to
21.897 - // do is traverse down to the lowest levels and copy things.
21.898 - Local<Type> type(zone, map->type());
21.899 - if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
21.900 - return NULL;
21.901 -
21.902 - return root;
21.903 -}
21.904 -
21.905 -static inline bool
21.906 -ArrayContainsCharBuffers(Type *type)
21.907 -{
21.908 - if (type->contained()->isArray())
21.909 - return ArrayContainsCharBuffers(type->contained());
21.910 - return type->isCharArray();
21.911 -}
21.912 -
21.913 -void
21.914 -BytecodeCompiler::visit(VariableDeclaration *node)
21.915 -{
21.916 - Variable *var = node->variable();
21.917 -
21.918 - Local<Type> type(zone_, var->type());
21.919 - if (type->isArray()) {
21.920 - Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
21.921 - __ note_position(node->pos());
21.922 -
21.923 - Local<Type> right(zone_);
21.924 - if (node->initialization())
21.925 - right = node->initialization()->type();
21.926 -
21.927 - // There are a few methods for allocating, here:
21.928 - // (1) If the array is fixed,
21.929 - // (a) Initializer not present,
21.930 - // NEWFIXED
21.931 - // (b) Left is const non-string:
21.932 - // <nothing>
21.933 - // (b) Otherwise:
21.934 - // NEWFIXED
21.935 - // COPYARRAY
21.936 - // (2) If the array is not fixed,
21.937 - // (a) Initializer is not present,
21.938 - // NEWEMPTY
21.939 - // (b) Initializer is not a string literal,
21.940 - // or left is const:
21.941 - // <nothing>
21.942 - // (c) Initializer is a string literal,
21.943 - // NEWSIZED
21.944 - // COPYARRAY
21.945 - //
21.946 -
21.947 - Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
21.948 - ? Heap::Tenure_Old
21.949 - : Heap::Tenure_Default;
21.950 -
21.951 - if (Expression *init = node->initialization()) {
21.952 - if (init->isArrayLiteral()) {
21.953 - unsigned maxsize = 0;
21.954 - Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
21.955 - if (!array)
21.956 - return;
21.957 -
21.958 - assert(type->isFixedLength());
21.959 -
21.960 - if (type->isConst()) {
21.961 - __ object(array);
21.962 - } else if (ArrayContainsCharBuffers(type)) {
21.963 - // This array contains mutable char buffers, so
21.964 - // unfortunately this gets a little more complicated. We
21.965 - // compute the maximum size needed for the innermost
21.966 - // string, which is similar to SP1. This means we can use
21.967 - // CopyArray rather than individually emit opcodes to clone
21.968 - // every string.
21.969 - Local<Type> child(zone_, type);
21.970 - for (size_t i = 0; i < type->levels() - 1; i++) {
21.971 - __ int_(child->fixedLength());
21.972 - child = child->contained();
21.973 - }
21.974 - __ int_(maxsize);
21.975 - __ newarray(OP_NEWSIZED, map, tenure);
21.976 - __ object(array);
21.977 - __ copyarray();
21.978 - } else {
21.979 - __ newarray(OP_NEWFIXED, map, tenure);
21.980 - __ object(array);
21.981 - __ copyarray();
21.982 - }
21.983 - } else if (type->isFixedLength()) {
21.984 - // Note in the case of:
21.985 - // const String:buffer[50] = "hello";
21.986 - //
21.987 - // We want to preserve sizeof(buffer) == 50.
21.988 - if (type->isConst() && !type->isCharArray()) {
21.989 - init->accept(this);
21.990 - } else {
21.991 - __ newarray(OP_NEWFIXED, map, tenure);
21.992 - init->accept(this);
21.993 - __ copyarray();
21.994 - }
21.995 - } else if (!type->isConst() && init->isStringLiteral()) {
21.996 - // This is a degenerate case of ArrayLiteral.
21.997 - __ int_(right->fixedLength());
21.998 - __ newarray(OP_NEWSIZED, map, tenure);
21.999 - init->accept(this);
21.1000 - __ copyarray();
21.1001 - } else if (type->isConst()) {
21.1002 - init->accept(this);
21.1003 - }
21.1004 - } else if (type->isFixedLength()) {
21.1005 - __ newarray(OP_NEWFIXED, map, tenure);
21.1006 - } else {
21.1007 -#if 0
21.1008 - if (node->postDimensions()) {
21.1009 - for (size_t i = 0; i < node->postDimensions()->length(); i++) {
21.1010 - Expression *expr = node->postDimensions()->at(i);
21.1011 - if (expr)
21.1012 - expr->accept(this);
21.1013 - else
21.1014 - __ int_(0);
21.1015 - }
21.1016 - __ newarray(OP_NEWSIZED, map, tenure);
21.1017 - } else {
21.1018 - __ newarray(OP_NEWEMPTY, map, tenure);
21.1019 - }
21.1020 -#endif
21.1021 - }
21.1022 - } else if (type->isStruct()) {
21.1023 - Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
21.1024 -
21.1025 - // Because structs can contain arrays, any sort of composition
21.1026 - // triggers non-LIFO allocation. This is just for correctness.
21.1027 - // We could do better by:
21.1028 - // (1) Limiting to structs that just (recursively) contain arrays,
21.1029 - // (2) Swap Stack for Default tenure in Struct::New
21.1030 - // (3) JIT analysis
21.1031 - if (var->scope()->kind() == Scope::GLOBAL)
21.1032 - __ newstruct(map, Heap::Tenure_Old);
21.1033 - else if (var->needsHeapAllocation() || map->composed())
21.1034 - __ newstruct(map, Heap::Tenure_Default);
21.1035 - else
21.1036 - __ newstruct(map, Heap::Tenure_Stack);
21.1037 - } else {
21.1038 - if (node->initialization()) {
21.1039 - node->initialization()->accept(this);
21.1040 - } else {
21.1041 - if (type->isInt32OrEnum() || type->isBool()) {
21.1042 - __ int_(0);
21.1043 - } else {
21.1044 - assert(type->isFloat());
21.1045 - __ float_(0);
21.1046 - }
21.1047 - }
21.1048 - }
21.1049 -
21.1050 - if (var->location() == Variable::STACK) {
21.1051 - __ setlocal(var);
21.1052 - locals_->set(zone_, var->slot(), var->type());
21.1053 - } else {
21.1054 - assert(var->location() == Variable::ENVIRONMENT);
21.1055 - setEnvSlot(var);
21.1056 - }
21.1057 -
21.1058 - __ pop();
21.1059 -}
21.1060 -
21.1061 -void
21.1062 -BytecodeCompiler::visit(CallExpression *node)
21.1063 -{
21.1064 -#if 0
21.1065 - Local<Type> funType(zone_, node->callee()->type());
21.1066 -
21.1067 - // Sniff out natives, which have a specific opcode and are guaranteed to
21.1068 - // be called via name proxy.
21.1069 - NamedFunction *native = NULL;
21.1070 - if (funType->isNative())
21.1071 - native = node->callee()->toNameProxy()->binding()->toNamedFunction();
21.1072 -
21.1073 - Local<Type> given(zone_);
21.1074 - for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
21.1075 - Expression *arg = node->arguments()->at(i);
21.1076 -
21.1077 - given = arg->type();
21.1078 -
21.1079 - // We need to compute a reference if the parameter was in the form:
21.1080 - // f(&a)
21.1081 - // Note this form does not allow: f({})
21.1082 - //
21.1083 - // We also need to compute references for all variadic native
21.1084 - // arguments, but arrays and references are already in the
21.1085 - // appropriate form.
21.1086 - bool mustPushReference = false;
21.1087 - if (i >= funType->parameters()->length()) {
21.1088 - assert(funType->isNative() && funType->isNativeVariadic());
21.1089 - mustPushReference = !given->isArray() && !given->isReference();
21.1090 - } else if (funType->parameterAt(i)->isReference()) {
21.1091 - mustPushReference = !given->isReference();
21.1092 - }
21.1093 -
21.1094 - // If a native is passed to a native, it must only be one level deep.
21.1095 - assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
21.1096 -
21.1097 - if (mustPushReference) {
21.1098 - if (arg->isNameProxy()) {
21.1099 - // :TODO: test with functions and globals
21.1100 - // Compute a reference to the name.
21.1101 - Variable *var = arg->toNameProxy()->binding()->toVariable();
21.1102 - __ note_position(node->pos());
21.1103 - __ newref(var);
21.1104 - } else if (arg->isFieldExpression()) {
21.1105 - FieldExpression *expr = arg->toFieldExpression();
21.1106 - expr->left()->accept(this);
21.1107 - __ note_position(expr->pos());
21.1108 - __ fieldref_lifo(expr->fieldIndex());
21.1109 - } else {
21.1110 - // We don't know how to, or can't, build a direct reference to
21.1111 - // this type. Make an indirect one, by taking the top of the
21.1112 - // stack and boxing it up.
21.1113 - arg->accept(this);
21.1114 - __ note_position(node->pos());
21.1115 - __ slotref_lifo();
21.1116 - }
21.1117 - } else {
21.1118 - arg->accept(this);
21.1119 - }
21.1120 - }
21.1121 -
21.1122 - unsigned argc = node->arguments()->length();
21.1123 -
21.1124 - // If there are missing arguments, then we're not done and have to push
21.1125 - // default parameters.
21.1126 - Local<Box> box(zone_);
21.1127 - Local<Array> array(zone_);
21.1128 - Local<ArrayMap> map(zone_);
21.1129 - for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
21.1130 - box = Box::cast(funType->defaults()->at(i));
21.1131 -
21.1132 - if (box->type()->isPod()) {
21.1133 - if (box->type()->pod() == PrimitiveType_Int32)
21.1134 - __ int_(box->toInt32());
21.1135 - else if (box->type()->pod() == PrimitiveType_Float)
21.1136 - __ float_(box->toFloat());
21.1137 - else
21.1138 - assert(false);
21.1139 -
21.1140 - if (funType->parameterAt(i)->isReference()) {
21.1141 - __ note_position(node->pos());
21.1142 - __ slotref_lifo();
21.1143 - }
21.1144 - } else {
21.1145 - assert(box->type()->isArray());
21.1146 -
21.1147 - array = Array::cast(box->toObject());
21.1148 - if (funType->parameterAt(i)->isConst()) {
21.1149 - __ object(array);
21.1150 - } else {
21.1151 - // We need to copy the array since it's mutable. Note that
21.1152 - // although COPYARRAY returns its left-hand side, this may
21.1153 - // change in the future, we do the same thing and dupe the
21.1154 - // newly allocated array.
21.1155 - map = ArrayMap::cast(array->map());
21.1156 -
21.1157 - // Natives cannot escape array references, so we can allocate
21.1158 - // them on the LIFO stack.
21.1159 - if (funType->isNative())
21.1160 - __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
21.1161 - else
21.1162 - __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
21.1163 - __ dup();
21.1164 - __ object(array);
21.1165 - __ copyarray();
21.1166 - __ pop();
21.1167 - }
21.1168 - }
21.1169 -
21.1170 - argc++;
21.1171 - }
21.1172 -
21.1173 - __ note_position(node->pos());
21.1174 - if (native) {
21.1175 - __ callnative(native->slot(), argc);
21.1176 - __ drop(argc);
21.1177 - } else {
21.1178 - node->callee()->accept(this);
21.1179 - __ call(funType);
21.1180 - __ drop(argc + 1);
21.1181 - }
21.1182 -#endif
21.1183 -}
21.1184 -
21.1185 -void
21.1186 -BytecodeCompiler::visit(TernaryExpression *node)
21.1187 -{
21.1188 - Label success, failure, join;
21.1189 -
21.1190 - visitForTest(node->condition(), &success, &failure, &success);
21.1191 - __ bind(&success);
21.1192 - node->left()->accept(this);
21.1193 - __ drop(1);
21.1194 - __ jump(&join);
21.1195 - __ bind(&failure);
21.1196 - node->right()->accept(this);
21.1197 - __ bind(&join);
21.1198 -}
21.1199 -
21.1200 -void
21.1201 -BytecodeCompiler::visit(IfStatement *node)
21.1202 -{
21.1203 - Label join;
21.1204 - if (!node->ifFalse()) {
21.1205 - Label success;
21.1206 -
21.1207 - visitForTest(node->condition(), &success, &join, &success);
21.1208 - __ bind(&success);
21.1209 - node->ifTrue()->accept(this);
21.1210 - } else {
21.1211 - Label success, next;
21.1212 -
21.1213 - visitForTest(node->condition(), &success, &next, &success);
21.1214 - __ bind(&success);
21.1215 - node->ifTrue()->accept(this);
21.1216 - __ jump(&join);
21.1217 - __ bind(&next);
21.1218 - node->ifFalse()->accept(this);
21.1219 - }
21.1220 -
21.1221 - __ bind(&join);
21.1222 -}
21.1223 -
21.1224 -bool
21.1225 -BytecodeCompiler::tableswitch(SwitchStatement *node)
21.1226 -{
21.1227 - CaseValueList *values = node->caseValueList();
21.1228 -
21.1229 - if (values->length() < 3)
21.1230 - return false;
21.1231 -
21.1232 - // Find the delta between the largest and smallest value.
21.1233 - int hi = values->at(values->length() - 1).box.toInt();
21.1234 - int lo = values->at(0).box.toInt();
21.1235 - assert(hi > lo);
21.1236 -
21.1237 - unsigned tablesize = TableSwitchEntries(lo, hi);
21.1238 - if (tablesize > MAX_TABLESWITCH_ENTRIES)
21.1239 - return false;
21.1240 -
21.1241 - Label def, join;
21.1242 -
21.1243 - // Create the list of labels that each statement will bind to.
21.1244 - Label *labels = new Label[node->cases()->length()];
21.1245 -
21.1246 - // Create the table of labels we'll use for each case.
21.1247 - Label **table = new Label *[tablesize];
21.1248 -
21.1249 - // Link all cases, by default, to the default label.
21.1250 - for (size_t i = 0; i < tablesize; i++)
21.1251 - table[i] = &def;
21.1252 -
21.1253 - // Now patch actual cases to their correct labels.
21.1254 - for (size_t i = 0; i < values->length(); i++) {
21.1255 - CaseValue &v = values->at(i);
21.1256 - assert(v.statement < node->cases()->length());
21.1257 -
21.1258 - unsigned index = unsigned(v.box.toInt() - lo);
21.1259 - assert(index < tablesize);
21.1260 -
21.1261 - table[index] = &labels[v.statement];
21.1262 - }
21.1263 -
21.1264 - // Emit the tableswitch opcode and the jump table.
21.1265 - __ tableswitch(lo, hi, &def, table);
21.1266 -
21.1267 - // We're done with the jump table now.
21.1268 - delete [] table;
21.1269 -
21.1270 - // Emit each statement.
21.1271 - for (size_t i = 0; i < node->cases()->length(); i++) {
21.1272 - Statement *stmt = node->cases()->at(i)->statement();
21.1273 -
21.1274 - __ bind(&labels[i]);
21.1275 - stmt->accept(this);
21.1276 - __ jump(&join);
21.1277 - }
21.1278 -
21.1279 - // We're done with the statement labels.
21.1280 - delete [] labels;
21.1281 -
21.1282 - // Emit the default case.
21.1283 - __ bind(&def);
21.1284 - if (node->defaultCase())
21.1285 - node->defaultCase()->accept(this);
21.1286 -
21.1287 - __ bind(&join);
21.1288 -
21.1289 - return true;
21.1290 -}
21.1291 -
21.1292 -void
21.1293 -BytecodeCompiler::visit(SwitchStatement *node)
21.1294 -{
21.1295 - node->expression()->accept(this);
21.1296 -
21.1297 - if (tableswitch(node))
21.1298 - return;
21.1299 -
21.1300 - Label join;
21.1301 -
21.1302 - for (size_t i = 0; i < node->cases()->length(); i++) {
21.1303 - Case *c = node->cases()->at(i);
21.1304 -
21.1305 - Label success, fail;
21.1306 - if (c->others()) {
21.1307 - for (size_t j = 0; j < c->others()->length(); j++) {
21.1308 - Expression *expr = c->others()->at(j);
21.1309 -
21.1310 - __ dup();
21.1311 - expr->accept(this);
21.1312 - __ j(OP_JEQ, &success);
21.1313 - }
21.1314 - }
21.1315 -
21.1316 - // The final test.
21.1317 - __ dup();
21.1318 - c->expression()->accept(this);
21.1319 - __ j(OP_JNE, &fail);
21.1320 - __ bind(&success);
21.1321 - c->statement()->accept(this);
21.1322 - __ jump(&join);
21.1323 - __ bind(&fail);
21.1324 - }
21.1325 -
21.1326 - if (node->defaultCase())
21.1327 - node->defaultCase()->accept(this);
21.1328 -
21.1329 - __ pop();
21.1330 - __ bind(&join);
21.1331 -}
21.1332 -
21.1333 -void
21.1334 -BytecodeCompiler::visit(FunctionStatement *node)
21.1335 -{
21.1336 - if (!node->fun()->used())
21.1337 - return;
21.1338 -
21.1339 - if (node->fun()->isNative()) {
21.1340 - assert(!moduleData_->natives->at(node->fun()->slot()));
21.1341 -
21.1342 - Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
21.1343 - Local<String> name(zone_, node->fun()->name());
21.1344 - Local<Native> native(zone_, Native::New(zone_, type, name));
21.1345 - if (!native)
21.1346 - return;
21.1347 -
21.1348 - moduleData_->natives->set(zone_, node->fun()->slot(), native);
21.1349 - return;
21.1350 - }
21.1351 -
21.1352 - // If the function has no body, then it's just a declaration.
21.1353 - if (!node->body()) {
21.1354 - assert(node->fun()->isForward() || node->fun()->isPublic());
21.1355 - return;
21.1356 - }
21.1357 -
21.1358 - BytecodeCompiler child(zone_, tree_, moduleData_);
21.1359 - Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
21.1360 - if (!fun)
21.1361 - return;
21.1362 -
21.1363 - assert(!moduleData_->module->getFunction(node->fun()->slot()));
21.1364 - moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
21.1365 -}
21.1366 -
21.1367 -void
21.1368 -BytecodeCompiler::visit(FunctionTypeStatement *node)
21.1369 -{
21.1370 -}
21.1371 -
21.1372 -void
21.1373 -BytecodeCompiler::visit(EnumStatement *node)
21.1374 -{
21.1375 -}
21.1376 -
21.1377 -void
21.1378 -BytecodeCompiler::visit(StructureStatement *node)
21.1379 -{
21.1380 -}
21.1381 -
21.1382 -void
21.1383 -BytecodeCompiler::visit(ArrayLiteral *node)
21.1384 -{
21.1385 - // We shouldn't reach these; they're handled manually when initializing
21.1386 - // declared arrays.
21.1387 - assert(false);
21.1388 -}
21.1389 -
21.1390 -void
21.1391 -BytecodeCompiler::visit(ImportStatement *node)
21.1392 -{
21.1393 -}
21.1394 -
21.1395 -Code *
21.1396 -BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
21.1397 -{
21.1398 - // STOP doubles as RETURNVOID.
21.1399 - __ stop();
21.1400 -
21.1401 - if (__ oom() || zone_->hasPendingException())
21.1402 - return NULL;
21.1403 -
21.1404 - Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
21.1405 - if (!bytes)
21.1406 - return NULL;
21.1407 - memcpy(bytes->raw(), __ buffer(), __ length());
21.1408 -
21.1409 - for (size_t i = 0; i < scope->maxContainedLocals(); i++)
21.1410 - assert(locals_->at(i));
21.1411 -
21.1412 - Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
21.1413 - if (!objects)
21.1414 - return NULL;
21.1415 -
21.1416 - for (size_t i = 0; i < __ objects()->length(); i++)
21.1417 - objects->set(zone_, i, *(__ objects()->at(i)));
21.1418 -
21.1419 - Local<ByteArray> safepoints(zone_);
21.1420 -
21.1421 - // If any stack slots hold gc pointers at potential failure points in the
21.1422 - // bytecode, record them now. We do this by building a list of tuples;
21.1423 - // each tuple contains the pc offset, and a bitset containing which stack
21.1424 - // slots must be scanned by the gc.
21.1425 - if (__ oopRecords()->length()) {
21.1426 - size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
21.1427 - size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
21.1428 - safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
21.1429 - if (!safepoints)
21.1430 - return NULL;
21.1431 -
21.1432 - Address cursor = safepoints->raw();
21.1433 - for (size_t i = 0; i < __ oopRecords()->length(); i++) {
21.1434 - OopRecord *record = __ oopRecords()->at(i);
21.1435 - assert(record->depth <= __ maxStackDepth());
21.1436 -
21.1437 - *reinterpret_cast<unsigned *>(cursor) = record->offset;
21.1438 -
21.1439 - unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
21.1440 - for (unsigned i = 0; i < record->depth; i++)
21.1441 - bits[i / 8] |= (1 << (i % 8));
21.1442 -
21.1443 - cursor += bytesPerSafepoint;
21.1444 - }
21.1445 -
21.1446 - assert(cursor == safepoints->raw() + gcmapSize);
21.1447 - }
21.1448 -
21.1449 - Local<ByteArray> sourcemap(zone_);
21.1450 - if (__ sourcemapLength()) {
21.1451 - sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
21.1452 - if (!sourcemap)
21.1453 - return NULL;
21.1454 -
21.1455 - memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
21.1456 - }
21.1457 -
21.1458 - Local<Code> code(zone_);
21.1459 -
21.1460 - code = Code::New(zone_,
21.1461 - bytes,
21.1462 - locals_,
21.1463 - objects,
21.1464 - __ maxStackDepth(),
21.1465 - moduleData_->module,
21.1466 - safepoints,
21.1467 - sourcemap,
21.1468 - lineno);
21.1469 - return code;
21.1470 -}
21.1471 -
21.1472 -Function *
21.1473 -BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
21.1474 -{
21.1475 - // Note: No need to record a life slot here, since it's part of the Frame.
21.1476 - AutoEnterScope functionScope(this, node->scope());
21.1477 -
21.1478 - // Set the initial line, because line mappings are deltas.
21.1479 - __ setFirstLine(node->pos().line);
21.1480 - locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
21.1481 -
21.1482 - node->body()->accept(this);
21.1483 -
21.1484 - unsigned nargs = node->scope()->numArguments();
21.1485 - Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
21.1486 - if (!args)
21.1487 - return NULL;
21.1488 -
21.1489 - for (size_t i = 0; i < node->scope()->numArguments(); i++)
21.1490 - args->set(zone_, i, node->scope()->getArgument(i)->type());
21.1491 -
21.1492 -
21.1493 - Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
21.1494 - if (!code)
21.1495 - return NULL;
21.1496 -
21.1497 - Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
21.1498 - Local<String> name(zone_, node->fun()->name());
21.1499 - Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
21.1500 - if (!fun)
21.1501 - return NULL;
21.1502 -
21.1503 - // If this function had a forward, export it as a named public.
21.1504 - if (node->fun()->isPublic()) {
21.1505 - assert(node->fun()->isPublic());
21.1506 - ScopedRoot<Function> root(fun);
21.1507 - if (!root)
21.1508 - return NULL;
21.1509 - if (!moduleData_->publics.append(root))
21.1510 - return NULL;
21.1511 - }
21.1512 -
21.1513 -#ifndef NDEBUG
21.1514 - Disassemble(code, stdout);
21.1515 -#endif
21.1516 -
21.1517 - return fun;
21.1518 -}
21.1519 -
21.1520 -Module *
21.1521 -BytecodeCompiler::compile()
21.1522 -{
21.1523 - AutoEnterScope scope(this, tree_->globalScope());
21.1524 -
21.1525 - ModuleData moduleData;
21.1526 -
21.1527 - moduleData_ = &moduleData;
21.1528 - moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
21.1529 -
21.1530 - if (!moduleData_)
21.1531 - return NULL;
21.1532 -
21.1533 - moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
21.1534 - if (!moduleData_->natives)
21.1535 - return NULL;
21.1536 -
21.1537 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
21.1538 - Statement *statement = tree_->statements()->at(i);
21.1539 - statement->accept(this);
21.1540 - }
21.1541 -
21.1542 - if (zone_->hasPendingException())
21.1543 - return NULL;
21.1544 -
21.1545 -#ifndef NDEBUG
21.1546 - for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
21.1547 - assert(moduleData_->module->getFunction(i));
21.1548 - for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
21.1549 - assert(moduleData_->natives->at(i));
21.1550 -#endif
21.1551 -
21.1552 - if (moduleData_->publics.length()) {
21.1553 - Local<Function> fun(zone_);
21.1554 - Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
21.1555 - Heap::Tenure_Old));
21.1556 - if (!list)
21.1557 - return NULL;
21.1558 -
21.1559 - for (size_t i = 0; i < moduleData_->publics.length(); i++)
21.1560 - list->set(zone_, i, moduleData_->publics[i]);
21.1561 -
21.1562 - moduleData_->module->setPublics(list);
21.1563 - }
21.1564 -
21.1565 - moduleData_->module->setNatives(moduleData_->natives);
21.1566 -
21.1567 - if (scope_->numEnvironmentVars()) {
21.1568 - Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
21.1569 - if (!globalMap)
21.1570 - return NULL;
21.1571 -
21.1572 - Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
21.1573 - if (!environment)
21.1574 - return NULL;
21.1575 -
21.1576 - moduleData_->module->setEnvironment(environment);
21.1577 - }
21.1578 -
21.1579 - Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
21.1580 - if (!code)
21.1581 - return NULL;
21.1582 -
21.1583 - Disassemble(code, stdout);
21.1584 -
21.1585 - moduleData_->module->setCode(code);
21.1586 -
21.1587 - return moduleData_->module;
21.1588 -}
21.1589 +/* vim: set ts=4 sw=4 tw=99 et:
21.1590 + *
21.1591 + * Copyright (C) 2012 David Anderson
21.1592 + *
21.1593 + * This file is part of JITCraft.
21.1594 + *
21.1595 + * JITCraft is free software: you can redistribute it and/or modify it under
21.1596 + * the terms of the GNU General Public License as published by the Free
21.1597 + * Software Foundation, either version 3 of the License, or (at your option)
21.1598 + * any later version.
21.1599 + *
21.1600 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
21.1601 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21.1602 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21.1603 + *
21.1604 + * You should have received a copy of the GNU General Public License along with
21.1605 + * JITCraft. If not, see http://www.gnu.org/licenses/.
21.1606 + */
21.1607 +#include <string.h>
21.1608 +#include "../Modules.h"
21.1609 +#include "../Types.h"
21.1610 +#include "../Array.h"
21.1611 +#include "../Strings.h"
21.1612 +#include "../Zone.h"
21.1613 +#include "../Environments.h"
21.1614 +#include "../Box.h"
21.1615 +#include "../Heap-inl.h"
21.1616 +#include "BytecodeCompiler.h"
21.1617 +#include "Scopes.h"
21.1618 +
21.1619 +using namespace ke;
21.1620 +
21.1621 +typedef BytecodeEmitter::Label Label;
21.1622 +
21.1623 +#define __ emitter_.
21.1624 +
21.1625 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
21.1626 + : zone_(zone),
21.1627 + tree_(tree),
21.1628 + emitter_(zone->pool()),
21.1629 + locals_(NULL),
21.1630 + scope_(NULL),
21.1631 + moduleData_(module),
21.1632 + loop_(NULL)
21.1633 +{
21.1634 +}
21.1635 +
21.1636 +static inline TokenKind
21.1637 +ToCompare(Expression *expr)
21.1638 +{
21.1639 + if (expr->isBinaryExpression()) {
21.1640 + BinaryExpression *b = expr->toBinaryExpression();
21.1641 + if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
21.1642 + return b->token();
21.1643 + } else if (expr->isUnaryExpression()) {
21.1644 + UnaryExpression *u = expr->toUnaryExpression();
21.1645 + if (u->token() == TOK_NOT)
21.1646 + return TOK_NOT;
21.1647 + }
21.1648 + return TOK_EOF;
21.1649 +}
21.1650 +
21.1651 +static inline Opcode
21.1652 +CompareTokenToJump(TokenKind kind)
21.1653 +{
21.1654 + switch (kind) {
21.1655 + case TOK_EQUALS:
21.1656 + return OP_JEQ;
21.1657 + case TOK_NOTEQUALS:
21.1658 + return OP_JNE;
21.1659 + case TOK_GT:
21.1660 + return OP_JG;
21.1661 + case TOK_GE:
21.1662 + return OP_JGE;
21.1663 + case TOK_LT:
21.1664 + return OP_JL;
21.1665 + default:
21.1666 + assert(kind == TOK_LE);
21.1667 + return OP_JLE;
21.1668 + }
21.1669 +}
21.1670 +
21.1671 +static inline Opcode
21.1672 +TokenToOpcode(TokenKind kind)
21.1673 +{
21.1674 + switch (kind) {
21.1675 + case TOK_PLUS:
21.1676 + return OP_ADD;
21.1677 + case TOK_MINUS:
21.1678 + return OP_SUB;
21.1679 + case TOK_STAR:
21.1680 + return OP_MUL;
21.1681 + case TOK_SLASH:
21.1682 + return OP_DIV;
21.1683 + case TOK_PERCENT:
21.1684 + return OP_MOD;
21.1685 + case TOK_SHR:
21.1686 + return OP_SHR;
21.1687 + case TOK_USHR:
21.1688 + return OP_USHR;
21.1689 + case TOK_SHL:
21.1690 + return OP_SHL;
21.1691 + case TOK_BITAND:
21.1692 + return OP_BITAND;
21.1693 + case TOK_BITOR:
21.1694 + return OP_BITOR;
21.1695 + case TOK_GT:
21.1696 + return OP_GT;
21.1697 + case TOK_GE:
21.1698 + return OP_GE;
21.1699 + case TOK_LT:
21.1700 + return OP_LT;
21.1701 + case TOK_LE:
21.1702 + return OP_LE;
21.1703 + case TOK_EQUALS:
21.1704 + return OP_EQ;
21.1705 + case TOK_NOTEQUALS:
21.1706 + return OP_NE;
21.1707 + default:
21.1708 + assert(kind == TOK_BITXOR);
21.1709 + return OP_BITXOR;
21.1710 + }
21.1711 +}
21.1712 +
21.1713 +void
21.1714 +BytecodeCompiler::recordLifoSlot(Scope *scope)
21.1715 +{
21.1716 + if (!scope)
21.1717 + return;
21.1718 +
21.1719 + if (Variable *var = scope->lifoSlot()) {
21.1720 + locals_->set(zone_, var->slot(), var->type());
21.1721 + __ savelifo(var->slot());
21.1722 + }
21.1723 +}
21.1724 +
21.1725 +void
21.1726 +BytecodeCompiler::unwindTo(Scope *scope)
21.1727 +{
21.1728 + // Note: we only need to unwind to the outermost scope's LIFO slot.
21.1729 + Variable *var = NULL;
21.1730 + for (Scope *current = scope_; current != scope; current = current->enclosing()) {
21.1731 + if (Variable *slot = current->lifoSlot())
21.1732 + var = slot;
21.1733 + }
21.1734 +
21.1735 + if (var)
21.1736 + __ unwindlifo(var->slot());
21.1737 +}
21.1738 +
21.1739 +void
21.1740 +BytecodeCompiler::visit(NameProxy *name)
21.1741 +{
21.1742 + switch (name->binding()->kind()) {
21.1743 + case BoundName::VARIABLE:
21.1744 + {
21.1745 + Variable *var = name->binding()->toVariable();
21.1746 +
21.1747 + if (var->location() == Variable::STACK) {
21.1748 + __ getlocal(var);
21.1749 + assert(!name->type()->isReference());
21.1750 + } else if (var->location() == Variable::ENVIRONMENT) {
21.1751 + getEnvSlot(var);
21.1752 + } else {
21.1753 + assert(var->location() == Variable::PARAMETER);
21.1754 + __ getarg(var);
21.1755 +
21.1756 + // If this argument is actually a reference, dereference it now.
21.1757 + if (var->type()->isReference())
21.1758 + __ getref(var->type()->contained());
21.1759 + }
21.1760 + break;
21.1761 + }
21.1762 +
21.1763 + case BoundName::FUNCTION:
21.1764 + {
21.1765 + NamedFunction *fun = name->binding()->toNamedFunction();
21.1766 + __ module();
21.1767 + __ getmodule_fn(fun->slot());
21.1768 + break;
21.1769 + }
21.1770 +
21.1771 + default:
21.1772 + {
21.1773 + NamedConstant *constant = name->binding()->toNamedConstant();
21.1774 + __ int_(constant->value().toInt());
21.1775 + break;
21.1776 + }
21.1777 + }
21.1778 +}
21.1779 +
21.1780 +void
21.1781 +BytecodeCompiler::visit(ExpressionStatement *node)
21.1782 +{
21.1783 + // Expressions leave their value on the top of the stack, so we make sure
21.1784 + // to balance the stack if they're used as a statement.
21.1785 + node->expression()->accept(this);
21.1786 + if (!node->expression()->type()->isVoid())
21.1787 + __ pop();
21.1788 +}
21.1789 +
21.1790 +static inline bool
21.1791 +IsCompositeValueType(Type *type)
21.1792 +{
21.1793 + return type->isStruct() ||
21.1794 + (type->isArray() && type->isFixedLength());
21.1795 +}
21.1796 +
21.1797 +static inline Array *
21.1798 +StringLiteralToArray(Zone *zone, StringLiteral *node)
21.1799 +{
21.1800 + Local<Type> type(zone, node->type());
21.1801 + Local<ArrayMap> map(zone, ArrayMap::Attach(zone, type));
21.1802 + if (!map)
21.1803 + return NULL;
21.1804 +
21.1805 + return Array::NewString(zone,
21.1806 + map,
21.1807 + node->string()->raw(),
21.1808 + node->string()->length(),
21.1809 + Heap::Tenure_Old);
21.1810 +}
21.1811 +
21.1812 +void
21.1813 +BytecodeCompiler::visit(Assignment *node)
21.1814 +{
21.1815 + Local<Type> left(zone_, node->type());
21.1816 + Local<Type> right(zone_, node->expression()->type());
21.1817 +
21.1818 + // The first step is three sub-steps:
21.1819 + //
21.1820 + // (1) Bind the left-hand side.
21.1821 + // -- If a cumulative operation (+=, etc):
21.1822 + // (2) Save a copy of the binding on the stack.
21.1823 + // (3) Dereference the binding to get a value.
21.1824 + //
21.1825 + if (node->lvalue()->isNameProxy()) {
21.1826 + NameProxy *proxy = node->lvalue()->toNameProxy();
21.1827 + Variable *var = proxy->binding()->toVariable();
21.1828 +
21.1829 + // We need to fetch the variable under the following circumstances:
21.1830 + // (1) The variable is a reference, since we'll store into the ref.
21.1831 + // (2) The variable is a fixed array, since we need to copy into it.
21.1832 + // (3) The variable is a struct, since we need to copy into it.
21.1833 + if (var->type()->isReference() || IsCompositeValueType(var->type()))
21.1834 + __ get(var);
21.1835 +
21.1836 + // Get the value if needed.
21.1837 + if (node->token() != TOK_ASSIGN) {
21.1838 + // += etc is not allowed on arrays.
21.1839 + assert(!var->type()->isArray());
21.1840 +
21.1841 + if (var->location() == Variable::ENVIRONMENT)
21.1842 + getEnvSlot(var);
21.1843 +
21.1844 + if (var->type()->isReference()) {
21.1845 + __ dup();
21.1846 + __ getref(var->type()->contained());
21.1847 + } else if (var->location() != Variable::ENVIRONMENT) {
21.1848 + __ get(var);
21.1849 + }
21.1850 + }
21.1851 + } else if (node->lvalue()->isFieldExpression()) {
21.1852 + FieldExpression *expr = node->lvalue()->toFieldExpression();
21.1853 + __ note_position(expr->pos());
21.1854 +
21.1855 + expr->left()->accept(this);
21.1856 +
21.1857 + if (node->token() != TOK_ASSIGN)
21.1858 + __ dup();
21.1859 +
21.1860 + if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
21.1861 + __ getfield(expr->fieldIndex(), left);
21.1862 + } else {
21.1863 + IndexExpression *index = node->lvalue()->toIndexExpression();
21.1864 + __ note_position(index->pos());
21.1865 +
21.1866 + index->left()->accept(this);
21.1867 + index->right()->accept(this);
21.1868 +
21.1869 + if (node->token() != TOK_ASSIGN)
21.1870 + __ dup2();
21.1871 +
21.1872 + if (node->token() != TOK_ASSIGN || IsCompositeValueType(left))
21.1873 + __ getelem(left);
21.1874 + }
21.1875 +
21.1876 + if (node->token() == TOK_ASSIGN) {
21.1877 + // Special case: if the left-hand side is a string literal, we must
21.1878 + // spawn a new copy (:TODO: something about const?)
21.1879 + if (node->expression()->isStringLiteral() && !left->isFixedLength()) {
21.1880 + Local<Array> string(zone_,
21.1881 + StringLiteralToArray(zone_, node->expression()->toStringLiteral()));
21.1882 + if (!string)
21.1883 + return;
21.1884 +
21.1885 + Local<ArrayMap> arrayMap(zone_, ArrayMap::cast(string->map()));
21.1886 + __ note_position(node->expression()->pos());
21.1887 + __ int_(string->length());
21.1888 + __ newarray(OP_NEWSIZED, arrayMap, Heap::Tenure_Default);
21.1889 + __ object(string);
21.1890 + __ copyarray();
21.1891 + } else {
21.1892 + node->expression()->accept(this);
21.1893 + }
21.1894 + } else {
21.1895 + visitForALU(left, node->expression());
21.1896 +
21.1897 + TokenKind alu = TokenKind(int(node->token()) - (TOK_ASSIGN_ADD - TOK_PLUS));
21.1898 + __ note_position(node->pos());
21.1899 + __ binary(TokenToOpcode(alu));
21.1900 + }
21.1901 +
21.1902 + // Emit the store.
21.1903 + if (left->isArray() && left->isFixedLength()) {
21.1904 + // (x = y) returns the left-hand side; if |x| is a fixed-length array,
21.1905 + // then |y| is as well, and we perform a deep copy.
21.1906 + assert(right->isFixedLength());
21.1907 + __ note_position(node->pos());
21.1908 + __ copyarray();
21.1909 + } else if (left->isStruct()) {
21.1910 + // Structs have value semantics, so emit a full copy. We don't break
21.1911 + // this down into u-ops, to avoid unnecessary bytecode explosion.
21.1912 + assert(right->isStruct());
21.1913 + __ note_position(node->pos());
21.1914 + __ copystruct();
21.1915 + } else if (node->lvalue()->isNameProxy()) {
21.1916 + NameProxy *proxy = node->lvalue()->toNameProxy();
21.1917 + Variable *var = proxy->binding()->toVariable();
21.1918 +
21.1919 + if (var->type()->isReference())
21.1920 + __ setref(var->type()->contained());
21.1921 + else if (var->location() == Variable::ENVIRONMENT)
21.1922 + setEnvSlot(var);
21.1923 + else
21.1924 + __ set(var);
21.1925 + } else if (node->lvalue()->isFieldExpression()) {
21.1926 + FieldExpression *expr = node->lvalue()->toFieldExpression();
21.1927 + __ setfield(expr->fieldIndex(), left);
21.1928 + } else {
21.1929 + __ setelem(left);
21.1930 + }
21.1931 +}
21.1932 +
21.1933 +void
21.1934 +BytecodeCompiler::visit(IncDecExpression *node)
21.1935 +{
21.1936 + // In the postfix case, the logic looks like:
21.1937 + // (1) Bind -> REF
21.1938 + // (2) Dup -> REF REF
21.1939 + // (3) Fetch -> REF VAL
21.1940 + // (4) Swap -> VAL REF
21.1941 + // (5) Pick -> VAL REF VAL
21.1942 + // (6) Add -> VAL REF VAL+1
21.1943 + // (7) Store -> VAL VAL+1
21.1944 + // (8) Drop -> VAL
21.1945 + //
21.1946 + // In the prefix case, the logic looks like:
21.1947 + // (1) Bind -> REF
21.1948 + // (2) Dup -> REF REF
21.1949 + // (3) Fetch -> REF VAL
21.1950 + // --
21.1951 + // --
21.1952 + // (6) Add -> REF VAL+1
21.1953 + // (7) Store -> VAL+1
21.1954 + // --
21.1955 + //
21.1956 + // This is squirrely enough such that we don't bother sharing too much
21.1957 + // with the above.
21.1958 + //
21.1959 + // Note: We simulate a "Pick" operation with a dup2+pop.
21.1960 +
21.1961 + // This is steps (1) to (5).
21.1962 + Expression *expr = node->expression();
21.1963 + if (expr->isNameProxy()) {
21.1964 + NameProxy *proxy = expr->toNameProxy();
21.1965 + Variable *var = proxy->binding()->toVariable();
21.1966 +
21.1967 + // Bind.
21.1968 + if (var->location() == Variable::ENVIRONMENT)
21.1969 + getEnvSlot(var);
21.1970 + else if (var->type()->isReference() || var->type()->isArray())
21.1971 + __ get(var);
21.1972 +
21.1973 + // Dup and fetch.
21.1974 + if (var->type()->isReference()) {
21.1975 + __ dup();
21.1976 + __ getref(node->type());
21.1977 + if (node->postfix()) {
21.1978 + __ swap();
21.1979 + __ pick2();
21.1980 + }
21.1981 + } else {
21.1982 + assert(!var->type()->isArray());
21.1983 + if (var->location() != Variable::ENVIRONMENT)
21.1984 + __ get(var);
21.1985 + if (node->postfix())
21.1986 + __ dup();
21.1987 + }
21.1988 + } else if (expr->isFieldExpression()) {
21.1989 + FieldExpression *field = expr->toFieldExpression();
21.1990 +
21.1991 + field->left()->accept(this);
21.1992 + __ dup();
21.1993 + __ getfield(field->fieldIndex(), field->type());
21.1994 +
21.1995 + if (node->postfix()) {
21.1996 + // The stack looks like this now:
21.1997 + // OBJECT VALUE
21.1998 + __ swap(); // VALUE OBJECT
21.1999 + __ pick2(); // VALUE OBJECT VALUE
21.2000 + }
21.2001 + } else {
21.2002 + IndexExpression *index = expr->toIndexExpression();
21.2003 + __ note_position(index->pos());
21.2004 +
21.2005 + index->left()->accept(this);
21.2006 + index->right()->accept(this);
21.2007 +
21.2008 + assert(!node->type()->isArray());
21.2009 + __ dup2();
21.2010 + __ getelem(node->type());
21.2011 +
21.2012 + if (node->postfix()) {
21.2013 + // The stack looks like this now:
21.2014 + // ARRAY INDEX VALUE
21.2015 + //
21.2016 + // So we must use a PICK operation to rotate the stack into position.
21.2017 + __ roll3(); // INDEX VALUE ARRAY
21.2018 + __ roll3(); // VALUE ARRAY INDEX
21.2019 + __ pick3(); // VALUE ARRAY INDEX VALUE
21.2020 + }
21.2021 + }
21.2022 +
21.2023 + // Perform step (6).
21.2024 + if (node->type()->isFloat()) {
21.2025 + __ float_(1.0);
21.2026 + } else {
21.2027 + assert(node->type()->isInt32());
21.2028 + __ int_(1);
21.2029 + }
21.2030 +
21.2031 + __ note_position(node->pos());
21.2032 + if (node->token() == TOK_INCREMENT)
21.2033 + __ binary(OP_ADD);
21.2034 + else
21.2035 + __ binary(OP_SUB);
21.2036 +
21.2037 + // Perform step (7).
21.2038 + if (expr->isNameProxy()) {
21.2039 + NameProxy *proxy = expr->toNameProxy();
21.2040 + Variable *var = proxy->binding()->toVariable();
21.2041 +
21.2042 + if (var->type()->isReference())
21.2043 + __ setref(node->type());
21.2044 + else if (var->location() == Variable::ENVIRONMENT)
21.2045 + setEnvSlot(var);
21.2046 + else
21.2047 + __ set(var);
21.2048 + } else if (expr->isFieldExpression()) {
21.2049 + FieldExpression *field = expr->toFieldExpression();
21.2050 + __ setfield(field->fieldIndex(), field->type());
21.2051 + } else {
21.2052 + assert(expr->isIndexExpression());
21.2053 + __ setelem(node->type());
21.2054 + }
21.2055 +
21.2056 + // Perform step (8).
21.2057 + if (node->postfix())
21.2058 + __ pop();
21.2059 +}
21.2060 +
21.2061 +void
21.2062 +BytecodeCompiler::visitForALU(Type *needed, Expression *node)
21.2063 +{
21.2064 + node->accept(this);
21.2065 + if (needed->isFloat() && !node->type()->isFloat())
21.2066 + __ cvt_i2f();
21.2067 + else
21.2068 + assert(needed->primitive() == node->type()->primitive());
21.2069 +}
21.2070 +
21.2071 +static inline Type *
21.2072 +GetCoercionType(TokenKind tok, Type *left, Type *right)
21.2073 +{
21.2074 + if (left->isFloat())
21.2075 + return left;
21.2076 + return right;
21.2077 +}
21.2078 +
21.2079 +void
21.2080 +BytecodeCompiler::visit(UnaryExpression *node)
21.2081 +{
21.2082 + Local<Type> out(zone_, ((Expression *)node)->type());
21.2083 +
21.2084 + switch (node->token()) {
21.2085 + case TOK_MINUS:
21.2086 + {
21.2087 + Local<Type> type(zone_, node->expression()->type());
21.2088 + node->expression()->accept(this);
21.2089 +
21.2090 + if (out->isFloat())
21.2091 + __ neg_f();
21.2092 + else
21.2093 + __ neg();
21.2094 + break;
21.2095 + }
21.2096 +
21.2097 + case TOK_NOT:
21.2098 + {
21.2099 + Local<Type> type(zone_, node->expression()->type());
21.2100 + node->expression()->accept(this);
21.2101 +
21.2102 + if (out->isFloat())
21.2103 + __ not_f();
21.2104 + else
21.2105 + __ not_();
21.2106 + break;
21.2107 + }
21.2108 +
21.2109 + case TOK_LABEL:
21.2110 + {
21.2111 + Local<Type> from(zone_, node->expression()->type());
21.2112 +
21.2113 + node->expression()->accept(this);
21.2114 + if (!from->isFloat() && out->isFloat())
21.2115 + __ bits_f2i();
21.2116 + else if (from->isFloat() && !out->isFloat())
21.2117 + __ bits_i2f();
21.2118 + break;
21.2119 + }
21.2120 +
21.2121 + case TOK_SIZEOF:
21.2122 + {
21.2123 + Local<Type> type(zone_, node->expression()->type());
21.2124 + if (type->isFixedLength()) {
21.2125 + __ int_(type->fixedLength());
21.2126 + } else {
21.2127 + node->expression()->accept(this);
21.2128 + __ sizeof_();
21.2129 + }
21.2130 + break;
21.2131 + }
21.2132 +
21.2133 + default:
21.2134 + assert(node->token() == TOK_TILDE);
21.2135 + node->expression()->accept(this);
21.2136 + __ bitnot();
21.2137 + break;
21.2138 + }
21.2139 +}
21.2140 +
21.2141 +void
21.2142 +BytecodeCompiler::visit(BinaryExpression *node)
21.2143 +{
21.2144 + if (node->token() == TOK_AND || node->token() == TOK_OR) {
21.2145 + Label success, failure, done;
21.2146 + visitForTest(node, &success, &failure, &success);
21.2147 + __ bind(&success);
21.2148 + __ int_(1);
21.2149 + __ drop(1); // Otherwise, the stack depth will be +1 too much.
21.2150 + __ jump(&done);
21.2151 + __ bind(&failure);
21.2152 + __ int_(0);
21.2153 + __ bind(&done);
21.2154 + return;
21.2155 + }
21.2156 +
21.2157 + Local<Type> leftType(zone_, node->left()->type());
21.2158 + Local<Type> rightType(zone_, node->right()->type());
21.2159 + Local<Type> coerce(zone_, GetCoercionType(node->token(), leftType, rightType));
21.2160 +
21.2161 + visitForALU(coerce, node->left());
21.2162 + visitForALU(coerce, node->right());
21.2163 +
21.2164 + Opcode op = TokenToOpcode(node->token());
21.2165 + if (node->type()->isFloat())
21.2166 + op = (Opcode)(int(op) + (OP_ADD_F - OP_ADD));
21.2167 +
21.2168 + __ note_position(node->pos());
21.2169 + __ binary(op);
21.2170 +}
21.2171 +
21.2172 +void
21.2173 +BytecodeCompiler::visit(IndexExpression *node)
21.2174 +{
21.2175 + node->left()->accept(this);
21.2176 + node->right()->accept(this);
21.2177 + __ note_position(node->pos());
21.2178 + __ getelem(node->type());
21.2179 +}
21.2180 +
21.2181 +void
21.2182 +BytecodeCompiler::visit(FieldExpression *node)
21.2183 +{
21.2184 + node->left()->accept(this);
21.2185 + __ getfield(node->fieldIndex(), node->type());
21.2186 +}
21.2187 +
21.2188 +void
21.2189 +BytecodeCompiler::visit(ReturnStatement *node)
21.2190 +{
21.2191 + if (node->expression()) {
21.2192 + node->expression()->accept(this);
21.2193 + __ return_();
21.2194 + } else {
21.2195 + __ returnvoid();
21.2196 + }
21.2197 +}
21.2198 +
21.2199 +void
21.2200 +BytecodeCompiler::visitForTest(Expression *expression,
21.2201 + Label *trueBranch,
21.2202 + Label *falseBranch,
21.2203 + Label *fallthrough)
21.2204 +{
21.2205 + TokenKind token = ToCompare(expression);
21.2206 + if (token == TOK_EOF || token == TOK_NOT) {
21.2207 + if (token == TOK_EOF)
21.2208 + expression->accept(this);
21.2209 + else
21.2210 + expression->toUnaryExpression()->expression()->accept(this);
21.2211 +
21.2212 + bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
21.2213 +
21.2214 + Opcode op = jumpOnTrue ? OP_JT : OP_JF;
21.2215 + if (expression->type()->isFloat())
21.2216 + op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
21.2217 +
21.2218 + if (fallthrough == falseBranch)
21.2219 + __ j(op, trueBranch);
21.2220 + else
21.2221 + __ j(op, falseBranch);
21.2222 + return;
21.2223 + }
21.2224 +
21.2225 + BinaryExpression *binary = expression->toBinaryExpression();
21.2226 +
21.2227 + if (token == TOK_AND || token == TOK_OR) {
21.2228 + Label next;
21.2229 + if (token == TOK_AND)
21.2230 + visitForTest(binary->left(), &next, falseBranch, &next);
21.2231 + else
21.2232 + visitForTest(binary->left(), trueBranch, &next, &next);
21.2233 + __ bind(&next);
21.2234 + visitForTest(binary->right(), trueBranch, falseBranch, fallthrough);
21.2235 + return;
21.2236 + }
21.2237 +
21.2238 + Opcode op = CompareTokenToJump(token);
21.2239 + if (fallthrough == trueBranch)
21.2240 + op = Invert(op);
21.2241 +
21.2242 + Local<Type> leftType(zone_, binary->left()->type());
21.2243 + Local<Type> rightType(zone_, binary->right()->type());
21.2244 + Local<Type> coerce(zone_, GetCoercionType(binary->token(), leftType, rightType));
21.2245 +
21.2246 + visitForALU(coerce, binary->left());
21.2247 + visitForALU(coerce, binary->right());
21.2248 + if (coerce->isFloat())
21.2249 + op = (Opcode)(int(op) + (OP_JL_F - OP_JL));
21.2250 +
21.2251 + if (fallthrough == trueBranch)
21.2252 + __ j(op, falseBranch);
21.2253 + else
21.2254 + __ j(op, trueBranch);
21.2255 +}
21.2256 +
21.2257 +void
21.2258 +BytecodeCompiler::visit(ForStatement *node)
21.2259 +{
21.2260 + AutoEnterScope forScope(this, node->scope());
21.2261 +
21.2262 + recordLifoSlot(node->scope());
21.2263 +
21.2264 + Label join, update;
21.2265 + LoopScope loop(scope_, &join, &update, &loop_);
21.2266 +
21.2267 + if (node->initialization())
21.2268 + node->initialization()->accept(this);
21.2269 +
21.2270 + Label header, test;
21.2271 + if (node->condition())
21.2272 + __ jump(&test);
21.2273 +
21.2274 + __ bind(&header);
21.2275 + node->body()->accept(this);
21.2276 +
21.2277 + __ bind(&update);
21.2278 + if (node->update())
21.2279 + node->update()->accept(this);
21.2280 +
21.2281 + if (node->condition()) {
21.2282 + __ bind(&test);
21.2283 + visitForTest(node->condition(), &header, &join, &join);
21.2284 + } else {
21.2285 + __ jump(&header);
21.2286 + }
21.2287 +
21.2288 + __ bind(&join);
21.2289 +
21.2290 + if (node->scope())
21.2291 + unwindTo(node->scope()->enclosing());
21.2292 + assert(__ stackDepth() == 0);
21.2293 +}
21.2294 +
21.2295 +void
21.2296 +BytecodeCompiler::visit(WhileStatement *node)
21.2297 +{
21.2298 + Label header, join;
21.2299 +
21.2300 + __ bind(&header);
21.2301 +
21.2302 + LoopScope loop(scope_, &join, &header, &loop_);
21.2303 +
21.2304 + if (node->token() == TOK_WHILE) {
21.2305 + Label body;
21.2306 +
21.2307 + visitForTest(node->condition(), &body, &join, &body);
21.2308 + __ bind(&body);
21.2309 + node->body()->accept(this);
21.2310 + __ jump(&header);
21.2311 + } else {
21.2312 + node->body()->accept(this);
21.2313 + visitForTest(node->condition(), &header, &join, &join);
21.2314 + }
21.2315 +
21.2316 + __ bind(&join);
21.2317 +}
21.2318 +
21.2319 +void
21.2320 +BytecodeCompiler::visit(BreakStatement *node)
21.2321 +{
21.2322 + unwindTo(loop_->scope());
21.2323 + __ jump(loop_->break_());
21.2324 +}
21.2325 +
21.2326 +void
21.2327 +BytecodeCompiler::visit(ContinueStatement *node)
21.2328 +{
21.2329 + unwindTo(loop_->scope());
21.2330 + __ jump(loop_->continue_());
21.2331 +}
21.2332 +
21.2333 +void
21.2334 +BytecodeCompiler::visit(BlockStatement *node)
21.2335 +{
21.2336 + AutoEnterScope blockScope(this, node->scope());
21.2337 +
21.2338 + recordLifoSlot(node->scope());
21.2339 +
21.2340 + for (size_t i = 0; i < node->statements()->length(); i++) {
21.2341 + Statement *statement = node->statements()->at(i);
21.2342 + statement->accept(this);
21.2343 + assert(__ stackDepth() == 0);
21.2344 + }
21.2345 +
21.2346 + // We don't bother emitting an "unwind" instruction for function scopes,
21.2347 + // since this is taken care of by the calling convention.
21.2348 + if (node->scope() && node->scope()->enclosing()->kind() != Scope::FUNCTION)
21.2349 + unwindTo(node->scope()->enclosing());
21.2350 +}
21.2351 +
21.2352 +void
21.2353 +BytecodeCompiler::visit(IntegerLiteral *node)
21.2354 +{
21.2355 + __ int_(node->value());
21.2356 +}
21.2357 +
21.2358 +void
21.2359 +BytecodeCompiler::visit(BooleanLiteral *node)
21.2360 +{
21.2361 + if (node->token() == TOK_TRUE)
21.2362 + __ true_();
21.2363 + else
21.2364 + __ false_();
21.2365 +}
21.2366 +
21.2367 +void
21.2368 +BytecodeCompiler::visit(FloatLiteral *node)
21.2369 +{
21.2370 + __ float_((float)node->value());
21.2371 +}
21.2372 +
21.2373 +void
21.2374 +BytecodeCompiler::visit(StringLiteral *node)
21.2375 +{
21.2376 + Local<Array> array(zone_, StringLiteralToArray(zone_, node));
21.2377 + if (!array)
21.2378 + return;
21.2379 +
21.2380 + __ note_position(node->pos());
21.2381 + __ object(array);
21.2382 +}
21.2383 +
21.2384 +void
21.2385 +BytecodeCompiler::getEnvSlot(Variable *var)
21.2386 +{
21.2387 + assert(var->scope()->kind() == Scope::GLOBAL);
21.2388 + __ getglobal(var);
21.2389 +}
21.2390 +
21.2391 +void
21.2392 +BytecodeCompiler::setEnvSlot(Variable *var)
21.2393 +{
21.2394 + assert(var->scope()->kind() == Scope::GLOBAL);
21.2395 + __ setglobal(var);
21.2396 +}
21.2397 +
21.2398 +static bool
21.2399 +FillArrayLiteral_String(Zone *zone, Handle<Array> array, ArrayLiteral *literal, unsigned *maxsize)
21.2400 +{
21.2401 + Local<Array> string(zone);
21.2402 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
21.2403 + Expression *expr = literal->expressions()->at(i);
21.2404 + StringLiteral *lit = expr->toStringLiteral();
21.2405 + if ((string = StringLiteralToArray(zone, lit)) == NULL)
21.2406 + return false;
21.2407 +
21.2408 + array->writeObject(zone, i, string);
21.2409 +
21.2410 + if (string->length() > *maxsize)
21.2411 + *maxsize = string->length();
21.2412 +
21.2413 + assert(!array->type()->contained()->isFixedLength() ||
21.2414 + array->type()->contained()->fixedLength() >= string->length());
21.2415 + }
21.2416 +
21.2417 + return true;
21.2418 +}
21.2419 +
21.2420 +static bool
21.2421 +FillArrayLiteral_Primitive(Zone *zone, Handle<Array> array, ArrayLiteral *literal)
21.2422 +{
21.2423 + assert(array->type()->fixedLength() == literal->expressions()->length());
21.2424 +
21.2425 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
21.2426 + Expression *expr = literal->expressions()->at(i);
21.2427 + if (IntegerLiteral *lit = expr->asIntegerLiteral()) {
21.2428 + array->writeInt32(i, lit->value());
21.2429 + continue;
21.2430 + }
21.2431 + if (BooleanLiteral *lit = expr->asBooleanLiteral()) {
21.2432 + if (lit->token() == TOK_TRUE)
21.2433 + array->writeInt32(i, 1);
21.2434 + else
21.2435 + array->writeInt32(i, 0);
21.2436 + continue;
21.2437 + }
21.2438 + if (FloatLiteral *lit = expr->asFloatLiteral()) {
21.2439 + array->writeFloat(i, (float)lit->value());
21.2440 + continue;
21.2441 + }
21.2442 +
21.2443 + // Unrecognized literal type.
21.2444 + assert(false);
21.2445 + }
21.2446 +
21.2447 + return true;
21.2448 +}
21.2449 +
21.2450 +static bool
21.2451 +TraverseArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<Array> array, Handle<Type> type,
21.2452 + unsigned *maxsize)
21.2453 +{
21.2454 + assert(type->fixedLength() == literal->expressions()->length());
21.2455 +
21.2456 + Local<Type> contained(zone, type->contained());
21.2457 + if (contained->isCharArray())
21.2458 + return FillArrayLiteral_String(zone, array, literal, maxsize);
21.2459 +
21.2460 + if (!contained->isArray())
21.2461 + return FillArrayLiteral_Primitive(zone, array, literal);
21.2462 +
21.2463 + Local<Array> subarray(zone);
21.2464 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
21.2465 + Expression *expr = literal->expressions()->at(i);
21.2466 + subarray = Array::cast(array->readObject(i));
21.2467 + if (!TraverseArrayLiteral(zone, expr->toArrayLiteral(), subarray, contained, maxsize))
21.2468 + return false;
21.2469 + }
21.2470 +
21.2471 + return true;
21.2472 +}
21.2473 +
21.2474 +static Array *
21.2475 +BuildArrayLiteral(Zone *zone, ArrayLiteral *literal, Handle<ArrayMap> map, unsigned *maxsize)
21.2476 +{
21.2477 + Local<Array> root(zone, Array::NewFixed(zone, map, Heap::Tenure_Old));
21.2478 + if (!root)
21.2479 + return NULL;
21.2480 +
21.2481 + // This should have allocated everything in the array, so all we need to
21.2482 + // do is traverse down to the lowest levels and copy things.
21.2483 + Local<Type> type(zone, map->type());
21.2484 + if (!TraverseArrayLiteral(zone, literal, root, type, maxsize))
21.2485 + return NULL;
21.2486 +
21.2487 + return root;
21.2488 +}
21.2489 +
21.2490 +static inline bool
21.2491 +ArrayContainsCharBuffers(Type *type)
21.2492 +{
21.2493 + if (type->contained()->isArray())
21.2494 + return ArrayContainsCharBuffers(type->contained());
21.2495 + return type->isCharArray();
21.2496 +}
21.2497 +
21.2498 +void
21.2499 +BytecodeCompiler::visit(VariableDeclaration *node)
21.2500 +{
21.2501 + Variable *var = node->variable();
21.2502 +
21.2503 + Local<Type> type(zone_, var->type());
21.2504 + if (type->isArray()) {
21.2505 + Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, type));
21.2506 + __ note_position(node->pos());
21.2507 +
21.2508 + Local<Type> right(zone_);
21.2509 + if (node->initialization())
21.2510 + right = node->initialization()->type();
21.2511 +
21.2512 + // There are a few methods for allocating, here:
21.2513 + // (1) If the array is fixed,
21.2514 + // (a) Initializer not present,
21.2515 + // NEWFIXED
21.2516 + // (b) Left is const non-string:
21.2517 + // <nothing>
21.2518 + // (b) Otherwise:
21.2519 + // NEWFIXED
21.2520 + // COPYARRAY
21.2521 + // (2) If the array is not fixed,
21.2522 + // (a) Initializer is not present,
21.2523 + // NEWEMPTY
21.2524 + // (b) Initializer is not a string literal,
21.2525 + // or left is const:
21.2526 + // <nothing>
21.2527 + // (c) Initializer is a string literal,
21.2528 + // NEWSIZED
21.2529 + // COPYARRAY
21.2530 + //
21.2531 +
21.2532 + Heap::Tenure tenure = var->scope()->kind() == Scope::GLOBAL
21.2533 + ? Heap::Tenure_Old
21.2534 + : Heap::Tenure_Default;
21.2535 +
21.2536 + if (Expression *init = node->initialization()) {
21.2537 + if (init->isArrayLiteral()) {
21.2538 + unsigned maxsize = 0;
21.2539 + Local<Array> array(zone_, BuildArrayLiteral(zone_, init->toArrayLiteral(), map, &maxsize));
21.2540 + if (!array)
21.2541 + return;
21.2542 +
21.2543 + assert(type->isFixedLength());
21.2544 +
21.2545 + if (type->isConst()) {
21.2546 + __ object(array);
21.2547 + } else if (ArrayContainsCharBuffers(type)) {
21.2548 + // This array contains mutable char buffers, so
21.2549 + // unfortunately this gets a little more complicated. We
21.2550 + // compute the maximum size needed for the innermost
21.2551 + // string, which is similar to SP1. This means we can use
21.2552 + // CopyArray rather than individually emit opcodes to clone
21.2553 + // every string.
21.2554 + Local<Type> child(zone_, type);
21.2555 + for (size_t i = 0; i < type->levels() - 1; i++) {
21.2556 + __ int_(child->fixedLength());
21.2557 + child = child->contained();
21.2558 + }
21.2559 + __ int_(maxsize);
21.2560 + __ newarray(OP_NEWSIZED, map, tenure);
21.2561 + __ object(array);
21.2562 + __ copyarray();
21.2563 + } else {
21.2564 + __ newarray(OP_NEWFIXED, map, tenure);
21.2565 + __ object(array);
21.2566 + __ copyarray();
21.2567 + }
21.2568 + } else if (type->isFixedLength()) {
21.2569 + // Note in the case of:
21.2570 + // const String:buffer[50] = "hello";
21.2571 + //
21.2572 + // We want to preserve sizeof(buffer) == 50.
21.2573 + if (type->isConst() && !type->isCharArray()) {
21.2574 + init->accept(this);
21.2575 + } else {
21.2576 + __ newarray(OP_NEWFIXED, map, tenure);
21.2577 + init->accept(this);
21.2578 + __ copyarray();
21.2579 + }
21.2580 + } else if (!type->isConst() && init->isStringLiteral()) {
21.2581 + // This is a degenerate case of ArrayLiteral.
21.2582 + __ int_(right->fixedLength());
21.2583 + __ newarray(OP_NEWSIZED, map, tenure);
21.2584 + init->accept(this);
21.2585 + __ copyarray();
21.2586 + } else if (type->isConst()) {
21.2587 + init->accept(this);
21.2588 + }
21.2589 + } else if (type->isFixedLength()) {
21.2590 + __ newarray(OP_NEWFIXED, map, tenure);
21.2591 + } else {
21.2592 +#if 0
21.2593 + if (node->postDimensions()) {
21.2594 + for (size_t i = 0; i < node->postDimensions()->length(); i++) {
21.2595 + Expression *expr = node->postDimensions()->at(i);
21.2596 + if (expr)
21.2597 + expr->accept(this);
21.2598 + else
21.2599 + __ int_(0);
21.2600 + }
21.2601 + __ newarray(OP_NEWSIZED, map, tenure);
21.2602 + } else {
21.2603 + __ newarray(OP_NEWEMPTY, map, tenure);
21.2604 + }
21.2605 +#endif
21.2606 + }
21.2607 + } else if (type->isStruct()) {
21.2608 + Local<StructMap> map(zone_, StructMap::cast(type->newMap()));
21.2609 +
21.2610 + // Because structs can contain arrays, any sort of composition
21.2611 + // triggers non-LIFO allocation. This is just for correctness.
21.2612 + // We could do better by:
21.2613 + // (1) Limiting to structs that just (recursively) contain arrays,
21.2614 + // (2) Swap Stack for Default tenure in Struct::New
21.2615 + // (3) JIT analysis
21.2616 + if (var->scope()->kind() == Scope::GLOBAL)
21.2617 + __ newstruct(map, Heap::Tenure_Old);
21.2618 + else if (var->needsHeapAllocation() || map->composed())
21.2619 + __ newstruct(map, Heap::Tenure_Default);
21.2620 + else
21.2621 + __ newstruct(map, Heap::Tenure_Stack);
21.2622 + } else {
21.2623 + if (node->initialization()) {
21.2624 + node->initialization()->accept(this);
21.2625 + } else {
21.2626 + if (type->isInt32OrEnum() || type->isBool()) {
21.2627 + __ int_(0);
21.2628 + } else {
21.2629 + assert(type->isFloat());
21.2630 + __ float_(0);
21.2631 + }
21.2632 + }
21.2633 + }
21.2634 +
21.2635 + if (var->location() == Variable::STACK) {
21.2636 + __ setlocal(var);
21.2637 + locals_->set(zone_, var->slot(), var->type());
21.2638 + } else {
21.2639 + assert(var->location() == Variable::ENVIRONMENT);
21.2640 + setEnvSlot(var);
21.2641 + }
21.2642 +
21.2643 + __ pop();
21.2644 +}
21.2645 +
21.2646 +void
21.2647 +BytecodeCompiler::visit(CallExpression *node)
21.2648 +{
21.2649 +#if 0
21.2650 + Local<Type> funType(zone_, node->callee()->type());
21.2651 +
21.2652 + // Sniff out natives, which have a specific opcode and are guaranteed to
21.2653 + // be called via name proxy.
21.2654 + NamedFunction *native = NULL;
21.2655 + if (funType->isNative())
21.2656 + native = node->callee()->toNameProxy()->binding()->toNamedFunction();
21.2657 +
21.2658 + Local<Type> given(zone_);
21.2659 + for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
21.2660 + Expression *arg = node->arguments()->at(i);
21.2661 +
21.2662 + given = arg->type();
21.2663 +
21.2664 + // We need to compute a reference if the parameter was in the form:
21.2665 + // f(&a)
21.2666 + // Note this form does not allow: f({})
21.2667 + //
21.2668 + // We also need to compute references for all variadic native
21.2669 + // arguments, but arrays and references are already in the
21.2670 + // appropriate form.
21.2671 + bool mustPushReference = false;
21.2672 + if (i >= funType->parameters()->length()) {
21.2673 + assert(funType->isNative() && funType->isNativeVariadic());
21.2674 + mustPushReference = !given->isArray() && !given->isReference();
21.2675 + } else if (funType->parameterAt(i)->isReference()) {
21.2676 + mustPushReference = !given->isReference();
21.2677 + }
21.2678 +
21.2679 + // If a native is passed to a native, it must only be one level deep.
21.2680 + assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
21.2681 +
21.2682 + if (mustPushReference) {
21.2683 + if (arg->isNameProxy()) {
21.2684 + // :TODO: test with functions and globals
21.2685 + // Compute a reference to the name.
21.2686 + Variable *var = arg->toNameProxy()->binding()->toVariable();
21.2687 + __ note_position(node->pos());
21.2688 + __ newref(var);
21.2689 + } else if (arg->isFieldExpression()) {
21.2690 + FieldExpression *expr = arg->toFieldExpression();
21.2691 + expr->left()->accept(this);
21.2692 + __ note_position(expr->pos());
21.2693 + __ fieldref_lifo(expr->fieldIndex());
21.2694 + } else {
21.2695 + // We don't know how to, or can't, build a direct reference to
21.2696 + // this type. Make an indirect one, by taking the top of the
21.2697 + // stack and boxing it up.
21.2698 + arg->accept(this);
21.2699 + __ note_position(node->pos());
21.2700 + __ slotref_lifo();
21.2701 + }
21.2702 + } else {
21.2703 + arg->accept(this);
21.2704 + }
21.2705 + }
21.2706 +
21.2707 + unsigned argc = node->arguments()->length();
21.2708 +
21.2709 + // If there are missing arguments, then we're not done and have to push
21.2710 + // default parameters.
21.2711 + Local<Box> box(zone_);
21.2712 + Local<Array> array(zone_);
21.2713 + Local<ArrayMap> map(zone_);
21.2714 + for (size_t i = node->arguments()->length(); i < funType->parameters()->length(); i++) {
21.2715 + box = Box::cast(funType->defaults()->at(i));
21.2716 +
21.2717 + if (box->type()->isPod()) {
21.2718 + if (box->type()->pod() == PrimitiveType_Int32)
21.2719 + __ int_(box->toInt32());
21.2720 + else if (box->type()->pod() == PrimitiveType_Float)
21.2721 + __ float_(box->toFloat());
21.2722 + else
21.2723 + assert(false);
21.2724 +
21.2725 + if (funType->parameterAt(i)->isReference()) {
21.2726 + __ note_position(node->pos());
21.2727 + __ slotref_lifo();
21.2728 + }
21.2729 + } else {
21.2730 + assert(box->type()->isArray());
21.2731 +
21.2732 + array = Array::cast(box->toObject());
21.2733 + if (funType->parameterAt(i)->isConst()) {
21.2734 + __ object(array);
21.2735 + } else {
21.2736 + // We need to copy the array since it's mutable. Note that
21.2737 + // although COPYARRAY returns its left-hand side, this may
21.2738 + // change in the future, we do the same thing and dupe the
21.2739 + // newly allocated array.
21.2740 + map = ArrayMap::cast(array->map());
21.2741 +
21.2742 + // Natives cannot escape array references, so we can allocate
21.2743 + // them on the LIFO stack.
21.2744 + if (funType->isNative())
21.2745 + __ newarray(OP_NEWFIXED, map, Heap::Tenure_Stack);
21.2746 + else
21.2747 + __ newarray(OP_NEWFIXED, map, Heap::Tenure_Default);
21.2748 + __ dup();
21.2749 + __ object(array);
21.2750 + __ copyarray();
21.2751 + __ pop();
21.2752 + }
21.2753 + }
21.2754 +
21.2755 + argc++;
21.2756 + }
21.2757 +
21.2758 + __ note_position(node->pos());
21.2759 + if (native) {
21.2760 + __ callnative(native->slot(), argc);
21.2761 + __ drop(argc);
21.2762 + } else {
21.2763 + node->callee()->accept(this);
21.2764 + __ call(funType);
21.2765 + __ drop(argc + 1);
21.2766 + }
21.2767 +#endif
21.2768 +}
21.2769 +
21.2770 +void
21.2771 +BytecodeCompiler::visit(TernaryExpression *node)
21.2772 +{
21.2773 + Label success, failure, join;
21.2774 +
21.2775 + visitForTest(node->condition(), &success, &failure, &success);
21.2776 + __ bind(&success);
21.2777 + node->left()->accept(this);
21.2778 + __ drop(1);
21.2779 + __ jump(&join);
21.2780 + __ bind(&failure);
21.2781 + node->right()->accept(this);
21.2782 + __ bind(&join);
21.2783 +}
21.2784 +
21.2785 +void
21.2786 +BytecodeCompiler::visit(IfStatement *node)
21.2787 +{
21.2788 + Label join;
21.2789 + if (!node->ifFalse()) {
21.2790 + Label success;
21.2791 +
21.2792 + visitForTest(node->condition(), &success, &join, &success);
21.2793 + __ bind(&success);
21.2794 + node->ifTrue()->accept(this);
21.2795 + } else {
21.2796 + Label success, next;
21.2797 +
21.2798 + visitForTest(node->condition(), &success, &next, &success);
21.2799 + __ bind(&success);
21.2800 + node->ifTrue()->accept(this);
21.2801 + __ jump(&join);
21.2802 + __ bind(&next);
21.2803 + node->ifFalse()->accept(this);
21.2804 + }
21.2805 +
21.2806 + __ bind(&join);
21.2807 +}
21.2808 +
21.2809 +bool
21.2810 +BytecodeCompiler::tableswitch(SwitchStatement *node)
21.2811 +{
21.2812 + CaseValueList *values = node->caseValueList();
21.2813 +
21.2814 + if (values->length() < 3)
21.2815 + return false;
21.2816 +
21.2817 + // Find the delta between the largest and smallest value.
21.2818 + int hi = values->at(values->length() - 1).box.toInt();
21.2819 + int lo = values->at(0).box.toInt();
21.2820 + assert(hi > lo);
21.2821 +
21.2822 + unsigned tablesize = TableSwitchEntries(lo, hi);
21.2823 + if (tablesize > MAX_TABLESWITCH_ENTRIES)
21.2824 + return false;
21.2825 +
21.2826 + Label def, join;
21.2827 +
21.2828 + // Create the list of labels that each statement will bind to.
21.2829 + Label *labels = new Label[node->cases()->length()];
21.2830 +
21.2831 + // Create the table of labels we'll use for each case.
21.2832 + Label **table = new Label *[tablesize];
21.2833 +
21.2834 + // Link all cases, by default, to the default label.
21.2835 + for (size_t i = 0; i < tablesize; i++)
21.2836 + table[i] = &def;
21.2837 +
21.2838 + // Now patch actual cases to their correct labels.
21.2839 + for (size_t i = 0; i < values->length(); i++) {
21.2840 + CaseValue &v = values->at(i);
21.2841 + assert(v.statement < node->cases()->length());
21.2842 +
21.2843 + unsigned index = unsigned(v.box.toInt() - lo);
21.2844 + assert(index < tablesize);
21.2845 +
21.2846 + table[index] = &labels[v.statement];
21.2847 + }
21.2848 +
21.2849 + // Emit the tableswitch opcode and the jump table.
21.2850 + __ tableswitch(lo, hi, &def, table);
21.2851 +
21.2852 + // We're done with the jump table now.
21.2853 + delete [] table;
21.2854 +
21.2855 + // Emit each statement.
21.2856 + for (size_t i = 0; i < node->cases()->length(); i++) {
21.2857 + Statement *stmt = node->cases()->at(i)->statement();
21.2858 +
21.2859 + __ bind(&labels[i]);
21.2860 + stmt->accept(this);
21.2861 + __ jump(&join);
21.2862 + }
21.2863 +
21.2864 + // We're done with the statement labels.
21.2865 + delete [] labels;
21.2866 +
21.2867 + // Emit the default case.
21.2868 + __ bind(&def);
21.2869 + if (node->defaultCase())
21.2870 + node->defaultCase()->accept(this);
21.2871 +
21.2872 + __ bind(&join);
21.2873 +
21.2874 + return true;
21.2875 +}
21.2876 +
21.2877 +void
21.2878 +BytecodeCompiler::visit(SwitchStatement *node)
21.2879 +{
21.2880 + node->expression()->accept(this);
21.2881 +
21.2882 + if (tableswitch(node))
21.2883 + return;
21.2884 +
21.2885 + Label join;
21.2886 +
21.2887 + for (size_t i = 0; i < node->cases()->length(); i++) {
21.2888 + Case *c = node->cases()->at(i);
21.2889 +
21.2890 + Label success, fail;
21.2891 + if (c->others()) {
21.2892 + for (size_t j = 0; j < c->others()->length(); j++) {
21.2893 + Expression *expr = c->others()->at(j);
21.2894 +
21.2895 + __ dup();
21.2896 + expr->accept(this);
21.2897 + __ j(OP_JEQ, &success);
21.2898 + }
21.2899 + }
21.2900 +
21.2901 + // The final test.
21.2902 + __ dup();
21.2903 + c->expression()->accept(this);
21.2904 + __ j(OP_JNE, &fail);
21.2905 + __ bind(&success);
21.2906 + c->statement()->accept(this);
21.2907 + __ jump(&join);
21.2908 + __ bind(&fail);
21.2909 + }
21.2910 +
21.2911 + if (node->defaultCase())
21.2912 + node->defaultCase()->accept(this);
21.2913 +
21.2914 + __ pop();
21.2915 + __ bind(&join);
21.2916 +}
21.2917 +
21.2918 +void
21.2919 +BytecodeCompiler::visit(FunctionStatement *node)
21.2920 +{
21.2921 + if (!node->fun()->used())
21.2922 + return;
21.2923 +
21.2924 + if (node->fun()->isNative()) {
21.2925 + assert(!moduleData_->natives->at(node->fun()->slot()));
21.2926 +
21.2927 + Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
21.2928 + Local<String> name(zone_, node->fun()->name());
21.2929 + Local<Native> native(zone_, Native::New(zone_, type, name));
21.2930 + if (!native)
21.2931 + return;
21.2932 +
21.2933 + moduleData_->natives->set(zone_, node->fun()->slot(), native);
21.2934 + return;
21.2935 + }
21.2936 +
21.2937 + // If the function has no body, then it's just a declaration.
21.2938 + if (!node->body()) {
21.2939 + assert(node->fun()->isForward() || node->fun()->isPublic());
21.2940 + return;
21.2941 + }
21.2942 +
21.2943 + BytecodeCompiler child(zone_, tree_, moduleData_);
21.2944 + Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
21.2945 + if (!fun)
21.2946 + return;
21.2947 +
21.2948 + assert(!moduleData_->module->getFunction(node->fun()->slot()));
21.2949 + moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
21.2950 +}
21.2951 +
21.2952 +void
21.2953 +BytecodeCompiler::visit(FunctionTypeStatement *node)
21.2954 +{
21.2955 +}
21.2956 +
21.2957 +void
21.2958 +BytecodeCompiler::visit(EnumStatement *node)
21.2959 +{
21.2960 +}
21.2961 +
21.2962 +void
21.2963 +BytecodeCompiler::visit(StructureStatement *node)
21.2964 +{
21.2965 +}
21.2966 +
21.2967 +void
21.2968 +BytecodeCompiler::visit(ArrayLiteral *node)
21.2969 +{
21.2970 + // We shouldn't reach these; they're handled manually when initializing
21.2971 + // declared arrays.
21.2972 + assert(false);
21.2973 +}
21.2974 +
21.2975 +void
21.2976 +BytecodeCompiler::visit(ImportStatement *node)
21.2977 +{
21.2978 +}
21.2979 +
21.2980 +Code *
21.2981 +BytecodeCompiler::compileCode(Scope *scope, unsigned lineno)
21.2982 +{
21.2983 + // STOP doubles as RETURNVOID.
21.2984 + __ stop();
21.2985 +
21.2986 + if (__ oom() || zone_->hasPendingException())
21.2987 + return NULL;
21.2988 +
21.2989 + Local<ByteArray> bytes(zone_, ByteArray::New(zone_, __ length() * sizeof(bytecode), Heap::Tenure_Old));
21.2990 + if (!bytes)
21.2991 + return NULL;
21.2992 + memcpy(bytes->raw(), __ buffer(), __ length());
21.2993 +
21.2994 + for (size_t i = 0; i < scope->maxContainedLocals(); i++)
21.2995 + assert(locals_->at(i));
21.2996 +
21.2997 + Local<FixedArray> objects(zone_, FixedArray::New(zone_, __ objects()->length(), Heap::Tenure_Old));
21.2998 + if (!objects)
21.2999 + return NULL;
21.3000 +
21.3001 + for (size_t i = 0; i < __ objects()->length(); i++)
21.3002 + objects->set(zone_, i, *(__ objects()->at(i)));
21.3003 +
21.3004 + Local<ByteArray> safepoints(zone_);
21.3005 +
21.3006 + // If any stack slots hold gc pointers at potential failure points in the
21.3007 + // bytecode, record them now. We do this by building a list of tuples;
21.3008 + // each tuple contains the pc offset, and a bitset containing which stack
21.3009 + // slots must be scanned by the gc.
21.3010 + if (__ oopRecords()->length()) {
21.3011 + size_t bytesPerSafepoint = Code::BytesPerSafepoint(__ maxStackDepth());
21.3012 + size_t gcmapSize = bytesPerSafepoint * __ oopRecords()->length();
21.3013 + safepoints = ByteArray::New(zone_, gcmapSize, Heap::Tenure_Old);
21.3014 + if (!safepoints)
21.3015 + return NULL;
21.3016 +
21.3017 + Address cursor = safepoints->raw();
21.3018 + for (size_t i = 0; i < __ oopRecords()->length(); i++) {
21.3019 + OopRecord *record = __ oopRecords()->at(i);
21.3020 + assert(record->depth <= __ maxStackDepth());
21.3021 +
21.3022 + *reinterpret_cast<unsigned *>(cursor) = record->offset;
21.3023 +
21.3024 + unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
21.3025 + for (unsigned i = 0; i < record->depth; i++)
21.3026 + bits[i / 8] |= (1 << (i % 8));
21.3027 +
21.3028 + cursor += bytesPerSafepoint;
21.3029 + }
21.3030 +
21.3031 + assert(cursor == safepoints->raw() + gcmapSize);
21.3032 + }
21.3033 +
21.3034 + Local<ByteArray> sourcemap(zone_);
21.3035 + if (__ sourcemapLength()) {
21.3036 + sourcemap = ByteArray::New(zone_, __ sourcemapLength(), Heap::Tenure_Old);
21.3037 + if (!sourcemap)
21.3038 + return NULL;
21.3039 +
21.3040 + memcpy(sourcemap->raw(), __ sourcemap(), __ sourcemapLength());
21.3041 + }
21.3042 +
21.3043 + Local<Code> code(zone_);
21.3044 +
21.3045 + code = Code::New(zone_,
21.3046 + bytes,
21.3047 + locals_,
21.3048 + objects,
21.3049 + __ maxStackDepth(),
21.3050 + moduleData_->module,
21.3051 + safepoints,
21.3052 + sourcemap,
21.3053 + lineno);
21.3054 + return code;
21.3055 +}
21.3056 +
21.3057 +Function *
21.3058 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
21.3059 +{
21.3060 + // Note: No need to record a life slot here, since it's part of the Frame.
21.3061 + AutoEnterScope functionScope(this, node->scope());
21.3062 +
21.3063 + // Set the initial line, because line mappings are deltas.
21.3064 + __ setFirstLine(node->pos().line);
21.3065 + locals_ = FixedArray::New(zone_, node->scope()->maxContainedLocals(), Heap::Tenure_Old);
21.3066 +
21.3067 + node->body()->accept(this);
21.3068 +
21.3069 + unsigned nargs = node->scope()->numArguments();
21.3070 + Local<FixedArray> args(zone_, FixedArray::New(zone_, nargs, Heap::Tenure_Old));
21.3071 + if (!args)
21.3072 + return NULL;
21.3073 +
21.3074 + for (size_t i = 0; i < node->scope()->numArguments(); i++)
21.3075 + args->set(zone_, i, node->scope()->getArgument(i)->type());
21.3076 +
21.3077 +
21.3078 + Local<Code> code(zone_, compileCode(node->scope(), node->pos().line));
21.3079 + if (!code)
21.3080 + return NULL;
21.3081 +
21.3082 + Local<FunctionType> type(zone_, FunctionType::cast(node->fun()->type()));
21.3083 + Local<String> name(zone_, node->fun()->name());
21.3084 + Local<Function> fun(zone_, Function::New(zone_, code, type, name, node->pos()));
21.3085 + if (!fun)
21.3086 + return NULL;
21.3087 +
21.3088 + // If this function had a forward, export it as a named public.
21.3089 + if (node->fun()->isPublic()) {
21.3090 + assert(node->fun()->isPublic());
21.3091 + ScopedRoot<Function> root(fun);
21.3092 + if (!root)
21.3093 + return NULL;
21.3094 + if (!moduleData_->publics.append(root))
21.3095 + return NULL;
21.3096 + }
21.3097 +
21.3098 +#ifndef NDEBUG
21.3099 + Disassemble(code, stdout);
21.3100 +#endif
21.3101 +
21.3102 + return fun;
21.3103 +}
21.3104 +
21.3105 +Module *
21.3106 +BytecodeCompiler::compile()
21.3107 +{
21.3108 + AutoEnterScope scope(this, tree_->globalScope());
21.3109 +
21.3110 + ModuleData moduleData;
21.3111 +
21.3112 + moduleData_ = &moduleData;
21.3113 + moduleData_->module = Module::New(zone_, tree_->globalScope()->numFunctions());
21.3114 +
21.3115 + if (!moduleData_)
21.3116 + return NULL;
21.3117 +
21.3118 + moduleData_->natives = FixedArray::New(zone_, tree_->globalScope()->numNatives(), Heap::Tenure_Old);
21.3119 + if (!moduleData_->natives)
21.3120 + return NULL;
21.3121 +
21.3122 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
21.3123 + Statement *statement = tree_->statements()->at(i);
21.3124 + statement->accept(this);
21.3125 + }
21.3126 +
21.3127 + if (zone_->hasPendingException())
21.3128 + return NULL;
21.3129 +
21.3130 +#ifndef NDEBUG
21.3131 + for (size_t i = 0; i < tree_->globalScope()->numFunctions(); i++)
21.3132 + assert(moduleData_->module->getFunction(i));
21.3133 + for (size_t i = 0; i < tree_->globalScope()->numNatives(); i++)
21.3134 + assert(moduleData_->natives->at(i));
21.3135 +#endif
21.3136 +
21.3137 + if (moduleData_->publics.length()) {
21.3138 + Local<Function> fun(zone_);
21.3139 + Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
21.3140 + Heap::Tenure_Old));
21.3141 + if (!list)
21.3142 + return NULL;
21.3143 +
21.3144 + for (size_t i = 0; i < moduleData_->publics.length(); i++)
21.3145 + list->set(zone_, i, moduleData_->publics[i]);
21.3146 +
21.3147 + moduleData_->module->setPublics(list);
21.3148 + }
21.3149 +
21.3150 + moduleData_->module->setNatives(moduleData_->natives);
21.3151 +
21.3152 + if (scope_->numEnvironmentVars()) {
21.3153 + Local<EnvironmentMap> globalMap(zone_, scope_->createEnvironmentMap(zone_));
21.3154 + if (!globalMap)
21.3155 + return NULL;
21.3156 +
21.3157 + Local<Environment> environment(zone_, Environment::New(zone_, globalMap));
21.3158 + if (!environment)
21.3159 + return NULL;
21.3160 +
21.3161 + moduleData_->module->setEnvironment(environment);
21.3162 + }
21.3163 +
21.3164 + Local<Code> code(zone_, compileCode(tree_->globalScope(), 1));
21.3165 + if (!code)
21.3166 + return NULL;
21.3167 +
21.3168 + Disassemble(code, stdout);
21.3169 +
21.3170 + moduleData_->module->setCode(code);
21.3171 +
21.3172 + return moduleData_->module;
21.3173 +}
22.1 --- a/src/OldByCo.h Mon Jun 10 00:46:29 2013 +0100
22.2 +++ b/src/OldByCo.h Mon Jun 10 01:04:43 2013 +0100
22.3 @@ -1,160 +1,160 @@
22.4 -/* vim: set ts=4 sw=4 tw=99 et:
22.5 - *
22.6 - * Copyright (C) 2012 David Anderson
22.7 - *
22.8 - * This file is part of JITCraft.
22.9 - *
22.10 - * JITCraft is free software: you can redistribute it and/or modify it under
22.11 - * the terms of the GNU General Public License as published by the Free
22.12 - * Software Foundation, either version 3 of the License, or (at your option)
22.13 - * any later version.
22.14 - *
22.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
22.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
22.18 - *
22.19 - * You should have received a copy of the GNU General Public License along with
22.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
22.21 - */
22.22 -#ifndef _include_bytecode_compiler_h_
22.23 -#define _include_bytecode_compiler_h_
22.24 -
22.25 -#include "../Functions.h"
22.26 -#include "AST.h"
22.27 -#include "BytecodeEmitter.h"
22.28 -
22.29 -namespace ke {
22.30 -
22.31 -class Module;
22.32 -class Array;
22.33 -class ArrayMap;
22.34 -
22.35 -struct ModuleData
22.36 -{
22.37 - ScopedRoot<Module> module;
22.38 - PoolList<ScopedRoot<Function> > publics;
22.39 - ScopedRoot<FixedArray> natives;
22.40 -};
22.41 -
22.42 -class BytecodeCompiler : public AstVisitor
22.43 -{
22.44 - Zone *zone_;
22.45 - ParseTree *tree_;
22.46 - BytecodeEmitter emitter_;
22.47 - ScopedRoot<FixedArray> locals_;
22.48 - Scope *scope_;
22.49 - ModuleData *moduleData_;
22.50 -
22.51 - class LoopScope
22.52 - {
22.53 - Scope *scope_;
22.54 - BytecodeEmitter::Label *bk_;
22.55 - BytecodeEmitter::Label *ct_;
22.56 - LoopScope **prevp_;
22.57 - LoopScope *prev_;
22.58 -
22.59 - public:
22.60 - LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
22.61 - LoopScope **prevp)
22.62 - : scope_(scope),
22.63 - bk_(bk),
22.64 - ct_(ct),
22.65 - prevp_(prevp),
22.66 - prev_(*prevp)
22.67 - {
22.68 - *prevp_ = this;
22.69 - }
22.70 -
22.71 - ~LoopScope()
22.72 - {
22.73 - *prevp_ = prev_;
22.74 - }
22.75 -
22.76 - BytecodeEmitter::Label *break_() {
22.77 - return bk_;
22.78 - }
22.79 - BytecodeEmitter::Label *continue_() {
22.80 - return ct_;
22.81 - }
22.82 - Scope *scope() {
22.83 - return scope_;
22.84 - }
22.85 - };
22.86 -
22.87 - LoopScope *loop_;
22.88 -
22.89 - public:
22.90 - class AutoEnterScope
22.91 - {
22.92 - BytecodeCompiler *bc_;
22.93 - Scope *saved_;
22.94 -
22.95 - public:
22.96 - AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
22.97 - : bc_(bc),
22.98 - saved_(bc->scope_)
22.99 - {
22.100 - if (scope)
22.101 - bc->scope_ = scope;
22.102 - }
22.103 - ~AutoEnterScope() {
22.104 - bc_->scope_ = saved_;
22.105 - }
22.106 - };
22.107 -
22.108 - private:
22.109 - void recordLifoSlot(Scope *scope);
22.110 - void unwindTo(Scope *scope);
22.111 - void visitForTest(Expression *expression,
22.112 - BytecodeEmitter::Label *trueBranch,
22.113 - BytecodeEmitter::Label *falseBranch,
22.114 - BytecodeEmitter::Label *fallthrough);
22.115 - Code *compileCode(Scope *scope, unsigned lineno);
22.116 - Function *compileFunction(ModuleData *module, FunctionStatement *fun);
22.117 - void visitForALU(Type *needed, Expression *node);
22.118 -
22.119 - void getEnvSlot(Variable *var);
22.120 - void setEnvSlot(Variable *var);
22.121 -
22.122 - bool tableswitch(SwitchStatement *node);
22.123 -
22.124 - public:
22.125 - BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
22.126 -
22.127 - Module *compile();
22.128 -
22.129 - public:
22.130 - void visit(NameProxy *name);
22.131 - void visit(Assignment *node);
22.132 - void visit(BinaryExpression *node);
22.133 - void visit(ReturnStatement *node);
22.134 - void visit(ForStatement *node);
22.135 - void visit(BlockStatement *node);
22.136 - void visit(VariableDeclaration *node);
22.137 - void visit(IntegerLiteral *node);
22.138 - void visit(BooleanLiteral *node);
22.139 - void visit(FloatLiteral *node);
22.140 - void visit(StringLiteral *node);
22.141 - void visit(ExpressionStatement *node);
22.142 - void visit(FunctionStatement *node);
22.143 - void visit(CallExpression *node);
22.144 - void visit(IfStatement *node);
22.145 - void visit(IndexExpression *node);
22.146 - void visit(EnumStatement *node);
22.147 - void visit(WhileStatement *node);
22.148 - void visit(BreakStatement *node);
22.149 - void visit(ContinueStatement *node);
22.150 - void visit(IncDecExpression *node);
22.151 - void visit(UnaryExpression *node);
22.152 - void visit(TernaryExpression *node);
22.153 - void visit(StructureStatement *node);
22.154 - void visit(FieldExpression *node);
22.155 - void visit(SwitchStatement *node);
22.156 - void visit(FunctionTypeStatement *node);
22.157 - void visit(ArrayLiteral *node);
22.158 - void visit(ImportStatement *node);
22.159 -};
22.160 -
22.161 -}
22.162 -
22.163 -#endif // _include_bytecode_generator_h_
22.164 +/* vim: set ts=4 sw=4 tw=99 et:
22.165 + *
22.166 + * Copyright (C) 2012 David Anderson
22.167 + *
22.168 + * This file is part of JITCraft.
22.169 + *
22.170 + * JITCraft is free software: you can redistribute it and/or modify it under
22.171 + * the terms of the GNU General Public License as published by the Free
22.172 + * Software Foundation, either version 3 of the License, or (at your option)
22.173 + * any later version.
22.174 + *
22.175 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
22.176 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22.177 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
22.178 + *
22.179 + * You should have received a copy of the GNU General Public License along with
22.180 + * JITCraft. If not, see http://www.gnu.org/licenses/.
22.181 + */
22.182 +#ifndef _include_bytecode_compiler_h_
22.183 +#define _include_bytecode_compiler_h_
22.184 +
22.185 +#include "../Functions.h"
22.186 +#include "AST.h"
22.187 +#include "BytecodeEmitter.h"
22.188 +
22.189 +namespace ke {
22.190 +
22.191 +class Module;
22.192 +class Array;
22.193 +class ArrayMap;
22.194 +
22.195 +struct ModuleData
22.196 +{
22.197 + ScopedRoot<Module> module;
22.198 + PoolList<ScopedRoot<Function> > publics;
22.199 + ScopedRoot<FixedArray> natives;
22.200 +};
22.201 +
22.202 +class BytecodeCompiler : public AstVisitor
22.203 +{
22.204 + Zone *zone_;
22.205 + ParseTree *tree_;
22.206 + BytecodeEmitter emitter_;
22.207 + ScopedRoot<FixedArray> locals_;
22.208 + Scope *scope_;
22.209 + ModuleData *moduleData_;
22.210 +
22.211 + class LoopScope
22.212 + {
22.213 + Scope *scope_;
22.214 + BytecodeEmitter::Label *bk_;
22.215 + BytecodeEmitter::Label *ct_;
22.216 + LoopScope **prevp_;
22.217 + LoopScope *prev_;
22.218 +
22.219 + public:
22.220 + LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
22.221 + LoopScope **prevp)
22.222 + : scope_(scope),
22.223 + bk_(bk),
22.224 + ct_(ct),
22.225 + prevp_(prevp),
22.226 + prev_(*prevp)
22.227 + {
22.228 + *prevp_ = this;
22.229 + }
22.230 +
22.231 + ~LoopScope()
22.232 + {
22.233 + *prevp_ = prev_;
22.234 + }
22.235 +
22.236 + BytecodeEmitter::Label *break_() {
22.237 + return bk_;
22.238 + }
22.239 + BytecodeEmitter::Label *continue_() {
22.240 + return ct_;
22.241 + }
22.242 + Scope *scope() {
22.243 + return scope_;
22.244 + }
22.245 + };
22.246 +
22.247 + LoopScope *loop_;
22.248 +
22.249 + public:
22.250 + class AutoEnterScope
22.251 + {
22.252 + BytecodeCompiler *bc_;
22.253 + Scope *saved_;
22.254 +
22.255 + public:
22.256 + AutoEnterScope(BytecodeCompiler *bc, Scope *scope)
22.257 + : bc_(bc),
22.258 + saved_(bc->scope_)
22.259 + {
22.260 + if (scope)
22.261 + bc->scope_ = scope;
22.262 + }
22.263 + ~AutoEnterScope() {
22.264 + bc_->scope_ = saved_;
22.265 + }
22.266 + };
22.267 +
22.268 + private:
22.269 + void recordLifoSlot(Scope *scope);
22.270 + void unwindTo(Scope *scope);
22.271 + void visitForTest(Expression *expression,
22.272 + BytecodeEmitter::Label *trueBranch,
22.273 + BytecodeEmitter::Label *falseBranch,
22.274 + BytecodeEmitter::Label *fallthrough);
22.275 + Code *compileCode(Scope *scope, unsigned lineno);
22.276 + Function *compileFunction(ModuleData *module, FunctionStatement *fun);
22.277 + void visitForALU(Type *needed, Expression *node);
22.278 +
22.279 + void getEnvSlot(Variable *var);
22.280 + void setEnvSlot(Variable *var);
22.281 +
22.282 + bool tableswitch(SwitchStatement *node);
22.283 +
22.284 + public:
22.285 + BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
22.286 +
22.287 + Module *compile();
22.288 +
22.289 + public:
22.290 + void visit(NameProxy *name);
22.291 + void visit(Assignment *node);
22.292 + void visit(BinaryExpression *node);
22.293 + void visit(ReturnStatement *node);
22.294 + void visit(ForStatement *node);
22.295 + void visit(BlockStatement *node);
22.296 + void visit(VariableDeclaration *node);
22.297 + void visit(IntegerLiteral *node);
22.298 + void visit(BooleanLiteral *node);
22.299 + void visit(FloatLiteral *node);
22.300 + void visit(StringLiteral *node);
22.301 + void visit(ExpressionStatement *node);
22.302 + void visit(FunctionStatement *node);
22.303 + void visit(CallExpression *node);
22.304 + void visit(IfStatement *node);
22.305 + void visit(IndexExpression *node);
22.306 + void visit(EnumStatement *node);
22.307 + void visit(WhileStatement *node);
22.308 + void visit(BreakStatement *node);
22.309 + void visit(ContinueStatement *node);
22.310 + void visit(IncDecExpression *node);
22.311 + void visit(UnaryExpression *node);
22.312 + void visit(TernaryExpression *node);
22.313 + void visit(StructureStatement *node);
22.314 + void visit(FieldExpression *node);
22.315 + void visit(SwitchStatement *node);
22.316 + void visit(FunctionTypeStatement *node);
22.317 + void visit(ArrayLiteral *node);
22.318 + void visit(ImportStatement *node);
22.319 +};
22.320 +
22.321 +}
22.322 +
22.323 +#endif // _include_bytecode_generator_h_
23.1 --- a/src/OldSema.cpp Mon Jun 10 00:46:29 2013 +0100
23.2 +++ b/src/OldSema.cpp Mon Jun 10 01:04:43 2013 +0100
23.3 @@ -1,1899 +1,1899 @@
23.4 -/* vim: set ts=4 sw=4 tw=99 et:
23.5 - *
23.6 - * Copyright (C) 2012 David Anderson
23.7 - *
23.8 - * This file is part of JITCraft.
23.9 - *
23.10 - * JITCraft is free software: you can redistribute it and/or modify it under
23.11 - * the terms of the GNU General Public License as published by the Free
23.12 - * Software Foundation, either version 3 of the License, or (at your option)
23.13 - * any later version.
23.14 - *
23.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
23.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
23.18 - *
23.19 - * You should have received a copy of the GNU General Public License along with
23.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
23.21 - */
23.22 -#include <string.h>
23.23 -#include "SemanticAnalysis.h"
23.24 -#include "../Types.h"
23.25 -#include "../Zone.h"
23.26 -#include "../TypeManager.h"
23.27 -#include "../Strings.h"
23.28 -#include "../Box.h"
23.29 -#include "../Array.h"
23.30 -#include "../Heap-inl.h"
23.31 -#include "Scopes.h"
23.32 -#include "NameBinding.h"
23.33 -
23.34 -using namespace ke;
23.35 -
23.36 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
23.37 - : zone_(zone),
23.38 - cc_(cc),
23.39 - tree_(tree),
23.40 - scope_(NULL),
23.41 - loop_(NULL)
23.42 -{
23.43 -}
23.44 -
23.45 -bool
23.46 -SemanticAnalysis::analyze()
23.47 -{
23.48 - assert(false);
23.49 - return false;
23.50 -}
23.51 -
23.52 -
23.53 -#if 0
23.54 -
23.55 -static inline bool
23.56 -IsPrimitiveType(Type *type, PrimitiveType primitive)
23.57 -{
23.58 - if (!type)
23.59 - return false;
23.60 -
23.61 - if (!type->isPrimitive())
23.62 - return false;
23.63 -
23.64 - return primitive == type->primitive();
23.65 -}
23.66 -
23.67 -static inline bool
23.68 -EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
23.69 - BoxedPrimitive *out)
23.70 -{
23.71 - switch (kind) {
23.72 - case TOK_PLUS:
23.73 - *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
23.74 - return true;
23.75 -
23.76 - case TOK_SHL:
23.77 - *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
23.78 - return true;
23.79 -
23.80 - default:
23.81 - return false;
23.82 - }
23.83 -}
23.84 -
23.85 -static inline bool
23.86 -EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
23.87 -{
23.88 - switch (kind) {
23.89 - case TOK_MINUS:
23.90 - *out = BoxedPrimitive::Int(-inner.toInt());
23.91 - return true;
23.92 -
23.93 - default:
23.94 - return false;
23.95 - }
23.96 -}
23.97 -
23.98 -static bool
23.99 -EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
23.100 -{
23.101 - switch (expression->kind()) {
23.102 - case AstNode::kBinaryExpression:
23.103 - {
23.104 - BoxedPrimitive left;
23.105 - BoxedPrimitive right;
23.106 - BinaryExpression *b = expression->toBinaryExpression();
23.107 - if (!EvaluateForConstant(b->left(), &left) ||
23.108 - !EvaluateForConstant(b->right(), &right))
23.109 - {
23.110 - return false;
23.111 - }
23.112 - return EvaluateBinaryOperation(b->token(), left, right, out);
23.113 - }
23.114 -
23.115 - case AstNode::kUnaryExpression:
23.116 - {
23.117 - BoxedPrimitive inner;
23.118 - UnaryExpression *u = expression->toUnaryExpression();
23.119 - if (!EvaluateForConstant(u->expression(), &inner))
23.120 - return false;
23.121 - return EvaluateUnaryOperation(u->token(), inner, out);
23.122 - }
23.123 -
23.124 - case AstNode::kNameProxy:
23.125 - {
23.126 - NameProxy *proxy = expression->toNameProxy();
23.127 - if (proxy->binding()->kind() != BoundName::CONSTANT)
23.128 - return false;
23.129 -
23.130 - NamedConstant *c = proxy->binding()->toNamedConstant();
23.131 - if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
23.132 - return false;
23.133 -
23.134 - *out = c->value();
23.135 - return true;
23.136 - }
23.137 -
23.138 - case AstNode::kBooleanLiteral:
23.139 - *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
23.140 - return true;
23.141 -
23.142 - case AstNode::kIntegerLiteral:
23.143 - *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
23.144 - return true;
23.145 -
23.146 - default:
23.147 - return false;
23.148 - }
23.149 -}
23.150 -
23.151 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
23.152 - : zone_(zone),
23.153 - cc_(cc),
23.154 - tree_(tree),
23.155 - scope_(NULL),
23.156 - loop_(NULL)
23.157 -{
23.158 -}
23.159 -
23.160 -bool
23.161 -SemanticAnalysis::analyze()
23.162 -{
23.163 - if (cc_.failures())
23.164 - return false;
23.165 -
23.166 - scope_ = tree_->globalScope();
23.167 - assert(scope_->kind() == Scope::GLOBAL);
23.168 -
23.169 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
23.170 - Statement *statement = tree_->statements()->at(i);
23.171 - if (statement->isFunctionStatement()) {
23.172 - FunctionStatement *funstmt = statement->toFunctionStatement();
23.173 - if (!preanalyze(funstmt))
23.174 - return false;
23.175 - } else if (statement->isEnumStatement()) {
23.176 - EnumStatement *enumstmt = statement->toEnumStatement();
23.177 -
23.178 - // We pre-fill global enum types, since they may occur in function
23.179 - // signatures. This should probably be somewhere else...
23.180 - enumstmt->accept(this);
23.181 - } else if (statement->isStructureStatement()) {
23.182 - StructureStatement *node = statement->toStructureStatement();
23.183 - node->accept(this);
23.184 - if (!node->decl()->type())
23.185 - return false;
23.186 - } else if (statement->isFunctionTypeStatement()) {
23.187 - FunctionTypeStatement *node = statement->toFunctionTypeStatement();
23.188 - node->accept(this);
23.189 - if (!node->decl()->type())
23.190 - return false;
23.191 - }
23.192 - }
23.193 -
23.194 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
23.195 - Statement *statement = tree_->statements()->at(i);
23.196 -
23.197 - // We can't double-process these. Maybe put this check somewhere else.
23.198 - if (statement->isEnumStatement())
23.199 - continue;
23.200 -
23.201 - statement->accept(this);
23.202 - }
23.203 -
23.204 - if (!determineLiveFunctions())
23.205 - return false;
23.206 -
23.207 - return !cc_.failures();
23.208 -}
23.209 -
23.210 -bool
23.211 -SemanticAnalysis::determineLiveFunctions()
23.212 -{
23.213 - Vector<NamedFunction *> worklist;
23.214 -
23.215 - // Add the root set.
23.216 - for (size_t i = 0; i < tree_->statements()->length(); i++) {
23.217 - Statement *statement = tree_->statements()->at(i);
23.218 - if (!statement->isFunctionStatement())
23.219 - continue;
23.220 -
23.221 - FunctionStatement *stmt = statement->toFunctionStatement();
23.222 - NamedFunction *fun = stmt->fun();
23.223 - if (!fun->used())
23.224 - continue;
23.225 -
23.226 - for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
23.227 - NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
23.228 -
23.229 - // Names in these lists are always unused, however, we mark them
23.230 - // as used while inserting into the work queue, to avoid double-
23.231 - // insertion.
23.232 - if (name->used())
23.233 - continue;
23.234 -
23.235 - if (!worklist.append(name))
23.236 - return false;
23.237 -
23.238 - name->setUsed();
23.239 - }
23.240 - }
23.241 -
23.242 - while (!worklist.empty()) {
23.243 - NamedFunction *fun = worklist.popCopy();
23.244 -
23.245 - for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
23.246 - NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
23.247 - if (name->used())
23.248 - continue;
23.249 - if (!worklist.append(name))
23.250 - return false;
23.251 - name->setUsed();
23.252 - }
23.253 - }
23.254 -
23.255 - return true;
23.256 -}
23.257 -
23.258 -Type *
23.259 -SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
23.260 -{
23.261 - if (!name)
23.262 - return zone_->types()->getPrimitive(PrimitiveType_Int32);
23.263 -
23.264 - if (name->kind() == BoundName::UNBOUND) {
23.265 - cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
23.266 - return NULL;
23.267 - }
23.268 -
23.269 - if (name->kind() != BoundName::TYPE) {
23.270 - cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
23.271 - return NULL;
23.272 - }
23.273 -
23.274 - if (!name->type())
23.275 - return NULL;
23.276 -
23.277 - return name->type();
23.278 -}
23.279 -
23.280 -Type *
23.281 -SemanticAnalysis::visitAndApplyType(Expression *expression)
23.282 -{
23.283 - expression->accept(this);
23.284 - return expression->type();
23.285 -}
23.286 -
23.287 -Type *
23.288 -SemanticAnalysis::visitForLoad(Expression *expression)
23.289 -{
23.290 - Local<Type> type(zone_, visitAndApplyType(expression));
23.291 - if (!type)
23.292 - return NULL;
23.293 -
23.294 - if (type->isReference()) {
23.295 - expression->setType(type->contained());
23.296 - } else if (expression->isCallExpression()) {
23.297 - if (type->isVoid()) {
23.298 - CallExpression *call = expression->toCallExpression();
23.299 - cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
23.300 - return NULL;
23.301 - }
23.302 - }
23.303 -
23.304 - return expression->type();
23.305 -}
23.306 -
23.307 -void
23.308 -SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
23.309 -{
23.310 - const char *op = TokenNames[token];
23.311 - const char *name = GetTypeName(type);
23.312 -
23.313 - cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
23.314 -}
23.315 -
23.316 -void
23.317 -SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
23.318 -{
23.319 - const char *op = TokenNames[token];
23.320 - const char *leftName = GetTypeName(left);
23.321 - const char *rightName = GetTypeName(right);
23.322 -
23.323 - cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
23.324 -}
23.325 -
23.326 -Type *
23.327 -SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
23.328 -{
23.329 - if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
23.330 - (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
23.331 - {
23.332 - // If either side is a float, the other side must be a float or int.
23.333 - if (left->isFloat() || right->isFloat()) {
23.334 - Type *floatType = left->isFloat() ? left : right;
23.335 - Type *other = left->isFloat() ? right : left;
23.336 - if (other->isFloat() || other->isInt32())
23.337 - return floatType;
23.338 - }
23.339 - }
23.340 -
23.341 - if (token == TOK_OR || token == TOK_AND) {
23.342 - if (!canTest(node, left) || !canTest(node, right))
23.343 - return NULL;
23.344 - return zone_->types()->getPrimitive(PrimitiveType_Bool);
23.345 - }
23.346 -
23.347 - if (token >= TOK_EQUALS && token <= TOK_GE) {
23.348 - if ((left->isFloat() || left->isInt32()) &&
23.349 - (right->isFloat() || right->isInt32()))
23.350 - {
23.351 - return zone_->types()->getPrimitive(PrimitiveType_Bool);
23.352 - }
23.353 - binaryTypeError(node, token, left, right);
23.354 - return NULL;
23.355 - }
23.356 -
23.357 - if (!left->isInt32() || !right->isInt32()) {
23.358 - binaryTypeError(node, token, left, right);
23.359 - return NULL;
23.360 - }
23.361 -
23.362 - return left;
23.363 -}
23.364 -
23.365 -bool
23.366 -SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
23.367 -{
23.368 - if (!type->isPrimitive() && !type->isEnum()) {
23.369 - cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
23.370 - return false;
23.371 - }
23.372 - return true;
23.373 -}
23.374 -
23.375 -Type *
23.376 -SemanticAnalysis::visitForLValue(Expression *expression)
23.377 -{
23.378 - if (expression->isIndexExpression()) {
23.379 - Type *type = visitAndApplyType(expression);
23.380 - if (!type)
23.381 - return NULL;
23.382 -
23.383 - // if (type->isConst()) {
23.384 - // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
23.385 - // return NULL;
23.386 - // }
23.387 -
23.388 - return type;
23.389 - }
23.390 -
23.391 - if (expression->isFieldExpression()) {
23.392 - Type *type = visitAndApplyType(expression);
23.393 - if (!type)
23.394 - return NULL;
23.395 -
23.396 - // if (expression->toFieldExpression()->left()->type()->isConst()) {
23.397 - // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
23.398 - // return NULL;
23.399 - // }
23.400 -
23.401 - return type;
23.402 - }
23.403 -
23.404 - if (!expression->isNameProxy()) {
23.405 - cc_.reportError(expression->pos(), Message_ExpectedLValue);
23.406 - return NULL;
23.407 - }
23.408 -
23.409 - NameProxy *proxy = expression->toNameProxy();
23.410 - if (!proxy->binding()->kind() == BoundName::VARIABLE) {
23.411 - cc_.reportError(expression->pos(), Message_ExpectedLValue);
23.412 - return NULL;
23.413 - }
23.414 -
23.415 - Variable *var = proxy->binding()->toVariable();
23.416 - if (!var->type())
23.417 - return NULL;
23.418 -
23.419 - if (var->type()->isReference()) {
23.420 - if (var->type()->isConst()) {
23.421 - cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
23.422 - return NULL;
23.423 - }
23.424 - return var->type()->contained();
23.425 - }
23.426 - return var->type();
23.427 -}
23.428 -
23.429 -SemanticAnalysis::ControlStatus
23.430 -SemanticAnalysis::visitForControl(Statement *statement)
23.431 -{
23.432 - ControlScope scope(&control_);
23.433 - statement->accept(this);
23.434 - return scope.status();
23.435 -}
23.436 -
23.437 -void
23.438 -SemanticAnalysis::visit(NameProxy *name)
23.439 -{
23.440 - BoundName *binding = name->binding();
23.441 -
23.442 - if (binding->scope()->kind() == Scope::GLOBAL) {
23.443 - if (!function_ || function_->isPublic()) {
23.444 - // Whatever we're referencing must be kept alive no matter what.
23.445 - // As such, we simply mark it used, and don't do anything special.
23.446 - binding->setUsed();
23.447 - } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
23.448 - // Otherwise, we're inside a normal stock or function. Since we
23.449 - // don't really know if we've been used yet, we shouldn't
23.450 - // prematurely references as alive. Instead, we keep a list of
23.451 - // which names have been used, so we can mark them later if needed.
23.452 - //
23.453 - // Note that we skip this step if the binding is already in the
23.454 - // root set.
23.455 - if (!function_->addUsedGlobal(binding))
23.456 - return;
23.457 - }
23.458 - }
23.459 -
23.460 - name->setType(binding->type());
23.461 -}
23.462 -
23.463 -void
23.464 -SemanticAnalysis::visit(Assignment *node)
23.465 -{
23.466 - Local<Type> exprType(zone_, visitForLoad(node->expression()));
23.467 - if (!exprType)
23.468 - return ;
23.469 -
23.470 - Local<Type> type(zone_, visitForLValue(node->lvalue()));
23.471 - if (!type)
23.472 - return;
23.473 -
23.474 - if (node->token() != TOK_ASSIGN) {
23.475 - if (!typeCheckBinary(node, node->token(), type, exprType))
23.476 - return;
23.477 - }
23.478 -
23.479 - if (!typeCheckAssignment(node->pos(), exprType, type, true))
23.480 - return;
23.481 -
23.482 - node->setType(type);
23.483 -}
23.484 -
23.485 -void
23.486 -SemanticAnalysis::visit(IncDecExpression *node)
23.487 -{
23.488 - Local<Type> type(zone_, visitForLValue(node->expression()));
23.489 - if (!type)
23.490 - return;
23.491 -
23.492 - assert(!type->isReference());
23.493 -
23.494 - if (!type->isInt32() && !type->isFloat()) {
23.495 - unaryTypeError(node, node->token(), type);
23.496 - return;
23.497 - }
23.498 -
23.499 - node->setType(type);
23.500 -}
23.501 -
23.502 -void
23.503 -SemanticAnalysis::visit(UnaryExpression *node)
23.504 -{
23.505 - Local<Type> type(zone_, visitForLoad(node->expression()));
23.506 - if (!type)
23.507 - return;
23.508 -
23.509 - switch (node->token())
23.510 - {
23.511 - case TOK_NOT:
23.512 - if (!canTest(node->expression(), type))
23.513 - return;
23.514 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
23.515 - if (!type)
23.516 - return;
23.517 - node->setType(type);
23.518 - break;
23.519 -
23.520 - case TOK_MINUS:
23.521 - if (!type->isFloat() && !type->isInt32()) {
23.522 - unaryTypeError(node, node->token(), type);
23.523 - return;
23.524 - }
23.525 - node->setType(type);
23.526 - break;
23.527 -
23.528 - case TOK_LABEL:
23.529 - {
23.530 - Local<Type> to(zone_, bindType(node->pos(), node->type()));
23.531 - if (!to)
23.532 - return;
23.533 -
23.534 - if ((!type->isFloat() && !type->isInt32OrEnum()) ||
23.535 - (!to->isFloat() && !to->isInt32OrEnum()))
23.536 - {
23.537 - unaryTypeError(node, node->token(), type);
23.538 - return;
23.539 - }
23.540 -
23.541 - node->setType(to);
23.542 - break;
23.543 - }
23.544 -
23.545 - case TOK_SIZEOF:
23.546 - {
23.547 - if (!type->isArray()) {
23.548 - cc_.reportError(node->pos(), Message_SizeofNeedsArray);
23.549 - return;
23.550 - }
23.551 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
23.552 - break;
23.553 - }
23.554 -
23.555 - default:
23.556 - assert(node->token() == TOK_TILDE);
23.557 - if (!type->isInt32()) {
23.558 - unaryTypeError(node, node->token(), type);
23.559 - return;
23.560 - }
23.561 - node->setType(type);
23.562 - break;
23.563 - }
23.564 -}
23.565 -
23.566 -void
23.567 -SemanticAnalysis::visit(TernaryExpression *node)
23.568 -{
23.569 - Local<Type> type(zone_, visitForLoad(node->condition()));
23.570 - if (!type)
23.571 - return;
23.572 -
23.573 - if (!canTest(node->condition(), type))
23.574 - return;
23.575 -
23.576 - Local<Type> left(zone_, visitForLoad(node->left()));
23.577 - Local<Type> right(zone_, visitForLoad(node->right()));
23.578 - if (!left || !right)
23.579 - return;
23.580 -
23.581 - if (left != right) {
23.582 - binaryTypeError(node, TOK_QMARK, left, right);
23.583 - return;
23.584 - }
23.585 -}
23.586 -
23.587 -void
23.588 -SemanticAnalysis::visit(BinaryExpression *node)
23.589 -{
23.590 - Local<Type> left(zone_, visitForLoad(node->left()));
23.591 - Local<Type> right(zone_, visitForLoad(node->right()));
23.592 - if (!left || !right)
23.593 - return;
23.594 -
23.595 - Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
23.596 - if (!result)
23.597 - return;
23.598 -
23.599 - node->setType(result);
23.600 -}
23.601 -
23.602 -void
23.603 -SemanticAnalysis::visit(ReturnStatement *node)
23.604 -{
23.605 - // Set this early, so if we error we don't get more errors.
23.606 - control_->returns(Returns_Always);
23.607 -
23.608 - if (!node->expression()) {
23.609 - if (!function_->type()->returnType()->isVoid())
23.610 - cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
23.611 - return;
23.612 - }
23.613 -
23.614 - Local<Type> type(zone_, visitForLoad(node->expression()));
23.615 - if (!type)
23.616 - return;
23.617 -
23.618 - Local<Type> returnType(zone_, function_->type()->returnType());
23.619 - if (!typeCheckAssignment(node->pos(), type, returnType, true))
23.620 - return;
23.621 -}
23.622 -
23.623 -void
23.624 -SemanticAnalysis::visit(ForStatement *node)
23.625 -{
23.626 - LoopScope loop(&loop_);
23.627 -
23.628 - if (node->scope())
23.629 - scope_ = node->scope();
23.630 -
23.631 - if (node->initialization())
23.632 - node->initialization()->accept(this);
23.633 -
23.634 - if (node->condition()) {
23.635 - Local<Type> type(zone_, visitForLoad(node->condition()));
23.636 - if (!type || !canTest(node->condition(), type)) {
23.637 - return;
23.638 - }
23.639 - }
23.640 -
23.641 - if (node->update())
23.642 - node->update()->accept(this);
23.643 -
23.644 - ControlStatus status = visitForControl(node->body());
23.645 -
23.646 - // If there is a condition, we treat this like a while loop. Otherwise,
23.647 - // join point is only reachable if the loop contains a break. The
23.648 - // termination status doesn't tell us anything yet.
23.649 - if (node->condition() || loop.breaks())
23.650 - control_->merge(status, ControlStatus(false, Returns_Never));
23.651 - else
23.652 - control_->terminate(status.returns());
23.653 -
23.654 - if (node->scope())
23.655 - scope_ = scope_->enclosing();
23.656 -}
23.657 -
23.658 -void
23.659 -SemanticAnalysis::visit(WhileStatement *node)
23.660 -{
23.661 - LoopScope loop(&loop_);
23.662 -
23.663 - Local<Type> type(zone_, visitForLoad(node->condition()));
23.664 - if (!type || !canTest(node->condition(), type)) {
23.665 - return;
23.666 - }
23.667 -
23.668 - ControlStatus status = visitForControl(node->body());
23.669 -
23.670 - // Detect loops that will always have a fork in the control-flow graph.
23.671 - // This will be a |while| loop, or a |do-while| loop whose body does
23.672 - // not terminate.
23.673 - //
23.674 - // For now, we treat these as an |if| regardless of the direction the
23.675 - // branch can take. That means the control-flow is always conditional.
23.676 - if (node->token() == TOK_WHILE ||
23.677 - !status.terminates() ||
23.678 - loop.breaks())
23.679 - {
23.680 - control_->merge(status, ControlStatus(false, Returns_Never));
23.681 - } else {
23.682 - // At this point, we've got a do-while loop with a |return| or
23.683 - // |continue|, meaning that the rest of the block is unreachable.
23.684 - control_->terminate(status.returns());
23.685 - }
23.686 -}
23.687 -
23.688 -void
23.689 -SemanticAnalysis::visit(BlockStatement *node)
23.690 -{
23.691 - if (node->scope())
23.692 - scope_ = node->scope();
23.693 - for (size_t i = 0; i < node->statements()->length(); i++) {
23.694 - Statement *statement = node->statements()->at(i);
23.695 - statement->accept(this);
23.696 - }
23.697 - if (node->scope())
23.698 - scope_ = scope_->enclosing();
23.699 -}
23.700 -
23.701 -static inline bool
23.702 -IsScalarString(Type *type)
23.703 -{
23.704 - if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
23.705 - return true;
23.706 - if (type->isReference())
23.707 - return IsScalarString(type->contained());
23.708 - return false;
23.709 -}
23.710 -
23.711 -static const int INFER_ARRAY_SIZE = 0;
23.712 -static const int EVAL_ARRAY_SIZE = -1;
23.713 -static const int DYNAMIC_ARRAY_SIZE = -2;
23.714 -
23.715 -bool
23.716 -SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
23.717 -{
23.718 - bool hadEmptySize = false;
23.719 -
23.720 - for (size_t i = 0; i < exprs->length(); i++) {
23.721 - Expression *expr = exprs->at(i);
23.722 - if (!expr) {
23.723 - dims[i] = INFER_ARRAY_SIZE;
23.724 - hadEmptySize = true;
23.725 - continue;
23.726 - }
23.727 -
23.728 - BoxedPrimitive box;
23.729 - if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
23.730 - int size = box.toInt();
23.731 - if (size <= 0) {
23.732 - cc_.reportError(expr->pos(), Message_BadArraySize);
23.733 - return false;
23.734 - }
23.735 -
23.736 - dims[i] = size;
23.737 - continue;
23.738 - }
23.739 -
23.740 - Local<Type> exprType(zone_, visitForLoad(expr));
23.741 - if (!exprType)
23.742 - return false;
23.743 -
23.744 - if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
23.745 - cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
23.746 - return false;
23.747 - }
23.748 -
23.749 - if (hadEmptySize) {
23.750 - cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
23.751 - return false;
23.752 - }
23.753 -
23.754 - dims[i] = EVAL_ARRAY_SIZE;
23.755 - }
23.756 -
23.757 - return true;
23.758 -}
23.759 -
23.760 -bool
23.761 -SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
23.762 - int dims[MAX_ARRAY_DEPTH],
23.763 - unsigned dimcount, unsigned level)
23.764 -{
23.765 - if (dims[level] == EVAL_ARRAY_SIZE) {
23.766 - cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
23.767 - return false;
23.768 - }
23.769 -
23.770 - if (dims[level] == INFER_ARRAY_SIZE) {
23.771 - // Strings always become dynamic arrays.
23.772 - if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
23.773 - dims[level] = literal->expressions()->length();
23.774 - } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
23.775 - cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
23.776 - return false;
23.777 - } else {
23.778 - if (literal->expressions()->length() != unsigned(dims[level])) {
23.779 - cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
23.780 - return false;
23.781 - }
23.782 - }
23.783 -
23.784 - if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
23.785 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
23.786 - Expression *expr = literal->expressions()->at(i);
23.787 - if (!expr->isStringLiteral()) {
23.788 - cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
23.789 - return false;
23.790 - }
23.791 -
23.792 - StringLiteral *lit = expr->toStringLiteral();
23.793 - if (dims[level + 1] > 0 &&
23.794 - unsigned(dims[level]) < lit->string()->length())
23.795 - {
23.796 - cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
23.797 - return false;
23.798 - }
23.799 - if (!visitAndApplyType(lit))
23.800 - return false;
23.801 - }
23.802 - } else if (level == dimcount - 1) {
23.803 - Local<Type> type(zone_);
23.804 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
23.805 - Expression *expr = literal->expressions()->at(i);
23.806 - if (expr->isArrayLiteral()) {
23.807 - cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
23.808 - return false;
23.809 - }
23.810 -
23.811 - if ((type = visitAndApplyType(expr)) == NULL)
23.812 - return false;
23.813 -
23.814 - if (!typeCheckAssignment(expr->pos(), type, contained, true))
23.815 - return false;
23.816 - }
23.817 - } else {
23.818 - for (size_t i = 0; i < literal->expressions()->length(); i++) {
23.819 - Expression *expr = literal->expressions()->at(i);
23.820 - if (!expr->isArrayLiteral()) {
23.821 - cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
23.822 - return false;
23.823 - }
23.824 -
23.825 - assert(expr->toArrayLiteral()->isFixed());
23.826 -
23.827 - if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
23.828 - contained,
23.829 - dims,
23.830 - dimcount,
23.831 - level + 1))
23.832 - {
23.833 - return false;
23.834 - }
23.835 - }
23.836 - }
23.837 -
23.838 - return true;
23.839 -}
23.840 -
23.841 -void
23.842 -SemanticAnalysis::visit(VariableDeclaration *node)
23.843 -{
23.844 - Local<Type> type(zone_, bindType(node->pos(), node->type()));
23.845 - if (!type)
23.846 - return;
23.847 -
23.848 -#if 0
23.849 - if (node->postDimensions() || type->isArray()) {
23.850 - // The type could be an array type, so sum the type and postDimensions
23.851 - // together.
23.852 - unsigned dimcount = node->postDimensions()->length();
23.853 - if (type->isArray())
23.854 - dimcount += type->levels();
23.855 - if (dimcount > MAX_ARRAY_DEPTH) {
23.856 - cc_.reportError(node->pos(), Message_MaximumArrayDepth);
23.857 - return;
23.858 - }
23.859 -
23.860 - // Take an initial guess at the array dimension sizes.
23.861 - int dims[MAX_ARRAY_DEPTH];
23.862 - if (!evaluateDimensions(node->postDimensions(), dims))
23.863 - return;
23.864 -
23.865 - // Now add in the type's array dimensions.
23.866 - Local<Type> contained(zone_, type);
23.867 - for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
23.868 - if (type->isFixedLength())
23.869 - dims[i] = type->fixedLength();
23.870 - else
23.871 - dims[i] = DYNAMIC_ARRAY_SIZE;
23.872 - contained = contained->contained();
23.873 - }
23.874 -
23.875 - Expression *initializer = node->initialization();
23.876 - if (initializer &&
23.877 - initializer->isArrayLiteral() &&
23.878 - initializer->toArrayLiteral()->isFixed())
23.879 - {
23.880 - // Fixed array initializers are special; we use them to infer any
23.881 - // missing information in the original array. We do not evaluate
23.882 - // the array initializer as an expression.
23.883 - if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
23.884 - contained,
23.885 - dims,
23.886 - dimcount,
23.887 - 0))
23.888 - {
23.889 - return;
23.890 - }
23.891 - initializer = NULL;
23.892 - }
23.893 -
23.894 - // We now have enough information to build the actual array type.
23.895 - // Start from the original dimcount, not the one computed for
23.896 - // initializers.
23.897 - for (size_t i = node->postDimensions()->length() - 1;
23.898 - i < node->postDimensions()->length();
23.899 - i--)
23.900 - {
23.901 - int size = dims[i] > 0
23.902 - ? dims[i]
23.903 - : Type::DYNAMIC_ARRAY_SIZE;
23.904 -
23.905 - type = zone_->types()->newArray(type, size, false);
23.906 - if (!type)
23.907 - return;
23.908 - }
23.909 -
23.910 - // Finally, if we had a non-fixed initializer, make sure it type
23.911 - // checks.
23.912 - if (initializer) {
23.913 - Local<Type> right(zone_, visitForLoad(initializer));
23.914 - if (!right)
23.915 - return;
23.916 -
23.917 - if (!typeCheckAssignment(node->pos(), right, type, true))
23.918 - return;
23.919 - }
23.920 - } else {
23.921 - if (node->initialization()) {
23.922 - Local<Type> right(zone_, visitForLoad(node->initialization()));
23.923 - if (!right)
23.924 - return;
23.925 - if (!typeCheckAssignment(node->pos(), right, type, true))
23.926 - return;
23.927 - }
23.928 -
23.929 - if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
23.930 - cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.931 - return;
23.932 - }
23.933 - }
23.934 -#endif
23.935 -
23.936 -#if 0
23.937 - // If this variable is stack allocated, we could use the LIFO heap
23.938 - // to allocate it. If that's the case, make sure to reserve a slot
23.939 - // so we can unwind the LIFO heap at the end of this scope.
23.940 - if (!node->variable()->needsHeapAllocation()) {
23.941 - if (type->isArray() || type->isStruct())
23.942 - scope_->setUsesLifoHeap();
23.943 - }
23.944 -
23.945 - node->variable()->setType(type);
23.946 -#endif
23.947 -}
23.948 -
23.949 -void
23.950 -SemanticAnalysis::visit(IntegerLiteral *node)
23.951 -{
23.952 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
23.953 -}
23.954 -
23.955 -void
23.956 -SemanticAnalysis::visit(BooleanLiteral *node)
23.957 -{
23.958 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
23.959 -}
23.960 -
23.961 -void
23.962 -SemanticAnalysis::visit(ExpressionStatement *node)
23.963 -{
23.964 - visitAndApplyType(node->expression());
23.965 -}
23.966 -
23.967 -Box *
23.968 -SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
23.969 -{
23.970 - Local<Type> given(zone_, visitForLoad(parameter->initializer()));
23.971 -
23.972 - BoxedPrimitive prim;
23.973 - if (EvaluateForConstant(parameter->initializer(), &prim)) {
23.974 - if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
23.975 - return NULL;
23.976 -
23.977 - if (prim.type() == PrimitiveType_Int32)
23.978 - return Box::New(zone_, given, prim.toInt());
23.979 - return Box::New(zone_, given, prim.toFloat());
23.980 - } else if (parameter->initializer()->isStringLiteral()) {
23.981 - StringLiteral *literal = parameter->initializer()->toStringLiteral();
23.982 -
23.983 - if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
23.984 - return NULL;
23.985 -
23.986 - Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
23.987 - if (!map)
23.988 - return NULL;
23.989 -
23.990 - Local<Array> array(zone_,
23.991 - Array::NewString(zone_,
23.992 - map,
23.993 - literal->string()->raw(),
23.994 - literal->string()->length(),
23.995 - Heap::Tenure_Old));
23.996 - if (!array)
23.997 - return NULL;
23.998 -
23.999 - return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
23.1000 - }
23.1001 -
23.1002 - cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
23.1003 - return NULL;
23.1004 -}
23.1005 -
23.1006 -bool
23.1007 -SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
23.1008 - FixedArray **argsp, FixedArray **defaultsp)
23.1009 -{
23.1010 - Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
23.1011 - if (!args)
23.1012 - return false;
23.1013 -
23.1014 - Local<FixedArray> defaults(zone_);
23.1015 -
23.1016 - // Apply types to arguments.
23.1017 - for (size_t i = 0; i < sig.parameters()->length(); i++) {
23.1018 - Parameter *parameter = sig.parameters()->at(i);
23.1019 -
23.1020 -#if 0
23.1021 - Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
23.1022 - if (!type)
23.1023 - return false;
23.1024 -
23.1025 - if (parameter->reference()) {
23.1026 - if (parameter->dimensions()) {
23.1027 - cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
23.1028 - return false;
23.1029 - }
23.1030 -
23.1031 - if (type->isStruct()) {
23.1032 - cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
23.1033 - return false;
23.1034 - }
23.1035 -
23.1036 - type = zone_->types()->getReference(type, parameter->isConst());
23.1037 - if (!type)
23.1038 - return false;
23.1039 - } else if (parameter->dimensions()) {
23.1040 - type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
23.1041 - if (!type)
23.1042 - return false;
23.1043 -
23.1044 - if (kind == TOK_NATIVE && type->levels() > 1) {
23.1045 - cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
23.1046 - return false;
23.1047 - }
23.1048 - }
23.1049 -
23.1050 - if (IsScalarString(type)) {
23.1051 - cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.1052 - return false;
23.1053 - }
23.1054 -
23.1055 - args->set(zone_, i, type);
23.1056 - parameter->variable()->setType(type);
23.1057 -
23.1058 - if (parameter->initializer()) {
23.1059 - if (!defaults) {
23.1060 - defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
23.1061 - if (!defaults)
23.1062 - return false;
23.1063 - }
23.1064 -
23.1065 - Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
23.1066 - if (!box)
23.1067 - return false;
23.1068 -
23.1069 - defaults->set(zone_, i, box);
23.1070 - }
23.1071 -#endif
23.1072 - }
23.1073 -
23.1074 - *argsp = args;
23.1075 - *defaultsp = defaults;
23.1076 -
23.1077 - return true;
23.1078 -}
23.1079 -
23.1080 -void
23.1081 -SemanticAnalysis::visit(FunctionTypeStatement *node)
23.1082 -{
23.1083 - if (node->decl()->type())
23.1084 - return;
23.1085 -
23.1086 - Local<FixedArray> args(zone_);
23.1087 - Local<FixedArray> defaults(zone_);
23.1088 -
23.1089 - const FunctionSignature &sig= node->signature();
23.1090 - if (!buildFunctionArgs(node,
23.1091 - TOK_STOCK,
23.1092 - sig,
23.1093 - args.address(),
23.1094 - defaults.address()))
23.1095 - {
23.1096 - return;
23.1097 - }
23.1098 -
23.1099 -#if 0
23.1100 - Local<Type> returnType(zone_);
23.1101 - if (sig.returnType())
23.1102 - returnType = bindType(node->pos(), sig.returnType());
23.1103 - else
23.1104 - returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
23.1105 -
23.1106 - if (!returnType)
23.1107 - return;
23.1108 -
23.1109 - Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
23.1110 - if (!funtype)
23.1111 - return;
23.1112 -
23.1113 - node->decl()->setType(funtype);
23.1114 -#endif
23.1115 -}
23.1116 -
23.1117 -Type *
23.1118 -SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
23.1119 -{
23.1120 - Local<Type> arrayType(zone_, type);
23.1121 -
23.1122 - unsigned dimcount = dimensions->length();
23.1123 - if (type->isArray())
23.1124 - dimcount += type->levels();
23.1125 -
23.1126 - if (dimcount > MAX_ARRAY_DEPTH) {
23.1127 - cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
23.1128 - Message_MaximumArrayDepth);
23.1129 - return false;
23.1130 - }
23.1131 -
23.1132 - // Note: constness is sort of bogus. Fix this sometime.
23.1133 - for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
23.1134 - Expression *expr = dimensions->at(i);
23.1135 - if (!expr) {
23.1136 - arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
23.1137 - if (!arrayType)
23.1138 - return NULL;
23.1139 -
23.1140 - continue;
23.1141 - }
23.1142 -
23.1143 - BoxedPrimitive box;
23.1144 - if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
23.1145 - cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
23.1146 - return NULL;
23.1147 - }
23.1148 -
23.1149 - if (box.toInt() <= 0) {
23.1150 - cc_.reportError(expr->pos(), Message_BadArraySize);
23.1151 - return NULL;
23.1152 - }
23.1153 -
23.1154 - arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
23.1155 - if (!arrayType)
23.1156 - return NULL;
23.1157 - }
23.1158 -
23.1159 - return arrayType;
23.1160 -}
23.1161 -
23.1162 -bool
23.1163 -SemanticAnalysis::preanalyze(FunctionStatement *node)
23.1164 -{
23.1165 - Local<FixedArray> args(zone_);
23.1166 - Local<FixedArray> defaults(zone_);
23.1167 -
23.1168 - const FunctionSignature &sig = node->signature();
23.1169 - if (!buildFunctionArgs(node,
23.1170 - node->fun()->token(),
23.1171 - sig,
23.1172 - args.address(),
23.1173 - defaults.address()))
23.1174 - {
23.1175 - return false;
23.1176 - }
23.1177 -
23.1178 -#if 0
23.1179 - Local<Type> returnType(zone_);
23.1180 - if (sig.returnType() ||
23.1181 - node->hasExplicitReturn() ||
23.1182 - node->fun()->isNative())
23.1183 - {
23.1184 - returnType = bindType(node->pos(), sig.returnType());
23.1185 - } else {
23.1186 - returnType = zone_->types()->getVoid();
23.1187 - }
23.1188 - if (!returnType)
23.1189 - return false;
23.1190 -
23.1191 - if (sig.returnDimensions()) {
23.1192 - returnType = buildArrayType(returnType, sig.returnDimensions(), false);
23.1193 - if (!returnType)
23.1194 - return false;
23.1195 - }
23.1196 -
23.1197 - if (IsScalarString(returnType)) {
23.1198 - cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.1199 - return false;
23.1200 - }
23.1201 -
23.1202 - Local<Type> funtype(zone_);
23.1203 - if (node->fun()->isNative())
23.1204 - funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
23.1205 - else
23.1206 - funtype = zone_->types()->newFunction(returnType, args, defaults);
23.1207 - if (!funtype)
23.1208 - return false;
23.1209 -
23.1210 - // If the function already has a type, it was forward declared before, and
23.1211 - // now this is our chance to type check the second declaration.
23.1212 - if (node->fun()->type()) {
23.1213 - Local<Type> forward(zone_, node->fun()->type());
23.1214 - if (!Type::Compare(funtype, forward)) {
23.1215 - cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
23.1216 - return false;
23.1217 - }
23.1218 - node->fun()->setForwardType(forward);
23.1219 - }
23.1220 -
23.1221 - node->fun()->setType(funtype);
23.1222 -#endif
23.1223 -
23.1224 - return true;
23.1225 -}
23.1226 -
23.1227 -void
23.1228 -SemanticAnalysis::visit(FunctionStatement *node)
23.1229 -{
23.1230 - function_ = node->fun();
23.1231 - scope_ = node->scope();
23.1232 -
23.1233 - ControlScope control(&control_);
23.1234 - if (node->body()) {
23.1235 - node->body()->accept(this);
23.1236 -
23.1237 - ControlStatus status = control.status();
23.1238 - if (status.returns() == Returns_Sometimes) {
23.1239 - cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
23.1240 - } else if (status.returns() == Returns_Never) {
23.1241 - if (!function_->type()->returnType()->isVoid())
23.1242 - cc_.reportError(node->pos(), Message_MissingReturnValue);
23.1243 - }
23.1244 - }
23.1245 -
23.1246 - scope_ = NULL;
23.1247 - function_ = NULL;
23.1248 -}
23.1249 -
23.1250 -void
23.1251 -SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
23.1252 -{
23.1253 - cc_.reportError(pos, Message_TypeMismatch,
23.1254 - GetTypeName(actual),
23.1255 - GetTypeName(given));
23.1256 -}
23.1257 -
23.1258 -bool
23.1259 -SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
23.1260 - Handle<Type> argActual, bool forAssign)
23.1261 -{
23.1262 - Local<Type> actual(zone_, argActual);
23.1263 - Local<Type> given(zone_, argGiven);
23.1264 -
23.1265 - if (!given->isArray()) {
23.1266 - cc_.reportError(pos, Message_ExpectedArray);
23.1267 - return false;
23.1268 - }
23.1269 - if (given->levels() != actual->levels()) {
23.1270 - cc_.reportError(pos, Message_ArrayDimensionsMismatch);
23.1271 - return false;
23.1272 - }
23.1273 -
23.1274 - unsigned level = 1;
23.1275 - while (given->isArray()) {
23.1276 - if (actual->isFixedLength()) {
23.1277 - if (forAssign) {
23.1278 - if (!given->isFixedLength()) {
23.1279 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
23.1280 - return false;
23.1281 - }
23.1282 -
23.1283 - if (actual->isCharArray()) {
23.1284 - // String assignment can have a truncated |given|.
23.1285 - if (given->fixedLength() > actual->fixedLength()) {
23.1286 - cc_.reportError(pos, Message_ArrayAssignmentTooBig);
23.1287 - return false;
23.1288 - }
23.1289 - } else {
23.1290 - if (given->fixedLength() != actual->fixedLength()) {
23.1291 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
23.1292 - return false;
23.1293 - }
23.1294 - }
23.1295 - }
23.1296 - } else if (given->isFixedLength()) {
23.1297 - // We do not allow assignments in the form:
23.1298 - // [][] = [][Y]
23.1299 - //
23.1300 - // Otherwise, the following code could break the size guarantees
23.1301 - // of the right-hand side:
23.1302 - //
23.1303 - // new x[][5];
23.1304 - // new y[][];
23.1305 - // new z[3];
23.1306 - //
23.1307 - // y = x;
23.1308 - // y[0] = z;
23.1309 - //
23.1310 - // Now |x[0]| contains a 4-length array.
23.1311 - if (level > 1) {
23.1312 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
23.1313 - return false;
23.1314 - }
23.1315 - }
23.1316 - given = given->contained();
23.1317 - actual = actual->contained();
23.1318 - level++;
23.1319 - }
23.1320 -
23.1321 - return typeCheckAssignment(pos, given, actual, forAssign);
23.1322 -}
23.1323 -
23.1324 -bool
23.1325 -SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
23.1326 - Handle<Type> argActual, bool forAssign)
23.1327 -{
23.1328 - Local<Type> actual(zone_, argActual);
23.1329 - Local<Type> given(zone_, argGiven);
23.1330 -
23.1331 - if (actual->isArray())
23.1332 - return typeCheckArrayAssignment(pos, given, actual, forAssign);
23.1333 -
23.1334 - if (given->isArray()) {
23.1335 - cc_.reportError(pos, Message_CannotAssignArrayToScalar);
23.1336 - return false;
23.1337 - }
23.1338 -
23.1339 - // The given type may not have been dereferenced.
23.1340 - if (given->isReference())
23.1341 - given = given->contained();
23.1342 - if (actual->isReference())
23.1343 - actual = actual->contained();
23.1344 -
23.1345 - // We coerce unchecked to a few things.
23.1346 - if (actual->isUnchecked() || given->isUnchecked()) {
23.1347 - Type *check = actual->isUnchecked() ? given : actual;
23.1348 - if (check->isUnchecked() ||
23.1349 - check->isEnum() ||
23.1350 - check->isInt32() ||
23.1351 - check->isBool() ||
23.1352 - check->isFloat())
23.1353 - {
23.1354 - return true;
23.1355 - }
23.1356 - typeMismatch(pos, actual, given);
23.1357 - return false;
23.1358 - }
23.1359 -
23.1360 - if (given->isFunction() && actual->isFunction()) {
23.1361 - if (!Type::Compare(given, actual)) {
23.1362 - typeMismatch(pos, actual, given);
23.1363 - return false;
23.1364 - }
23.1365 - return true;
23.1366 - }
23.1367 -
23.1368 - if (actual->isEnum()) {
23.1369 - if (!given->isEnum() || actual != given) {
23.1370 - typeMismatch(pos, actual, given);
23.1371 - return false;
23.1372 - }
23.1373 - return true;
23.1374 - }
23.1375 -
23.1376 - if (actual->isStruct()) {
23.1377 - if (!given->isStruct() || actual != given) {
23.1378 - typeMismatch(pos, actual, given);
23.1379 - return false;
23.1380 - }
23.1381 - return true;
23.1382 - }
23.1383 -
23.1384 - if (given->isEnum() || given->isFunction() || given->isStruct()) {
23.1385 - typeMismatch(pos, actual, given);
23.1386 - return false;
23.1387 - }
23.1388 -
23.1389 - // This coercion is trivial.
23.1390 - if (given->isBool() && actual->isInt32())
23.1391 - return true;
23.1392 -
23.1393 - if (given->primitive() != actual->primitive()) {
23.1394 - typeMismatch(pos, actual, given);
23.1395 - return false;
23.1396 - }
23.1397 -
23.1398 - return true;
23.1399 -}
23.1400 -
23.1401 -bool
23.1402 -SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
23.1403 -{
23.1404 - return typeCheckAssignment(node->pos(), given, actual, false);
23.1405 -}
23.1406 -
23.1407 -bool
23.1408 -SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
23.1409 -{
23.1410 - if (type->parameters()->length() == actual)
23.1411 - return true;
23.1412 -
23.1413 - if (actual > type->parameters()->length()) {
23.1414 - if (!type->isNative() || !type->isNativeVariadic())
23.1415 - return false;
23.1416 - return true;
23.1417 - }
23.1418 -
23.1419 - if (!type->defaults())
23.1420 - return false;
23.1421 -
23.1422 - // Missing arguments. See if there's a default argument for each missing
23.1423 - // actual.
23.1424 - for (unsigned i = actual; i < type->parameters()->length(); i++) {
23.1425 - if (!type->defaults()->at(i))
23.1426 - return false;
23.1427 - }
23.1428 -
23.1429 - return true;
23.1430 -}
23.1431 -
23.1432 -void
23.1433 -SemanticAnalysis::visit(CallExpression *node)
23.1434 -{
23.1435 - Local<Type> type(zone_, visitForLoad(node->callee()));
23.1436 - if (!type)
23.1437 - return;
23.1438 -
23.1439 - if (!type->isFunction()) {
23.1440 - cc_.reportError(node->pos(), Message_CalleeNotFunction);
23.1441 - return;
23.1442 - }
23.1443 -
23.1444 - if (!checkArgumentCount(type, node->arguments()->length())) {
23.1445 - cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
23.1446 - return;
23.1447 - }
23.1448 -
23.1449 - // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
23.1450 - // if (fun->isForward()) {
23.1451 - // cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
23.1452 - // return;
23.1453 - // }
23.1454 -
23.1455 - for (unsigned i = 0; i < node->arguments()->length(); i++) {
23.1456 - // Note: we don't compute references unless the callee needs a
23.1457 - // reference type.
23.1458 - Expression *expression = node->arguments()->at(i);
23.1459 - Local<Type> given(zone_, visitAndApplyType(expression));
23.1460 - if (!given)
23.1461 - return;
23.1462 -
23.1463 - // Since we skip a load, check for a call expression that returns void.
23.1464 - if (given->isVoid()) {
23.1465 - assert(expression->isCallExpression());
23.1466 - CallExpression *call = expression->toCallExpression();
23.1467 - cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
23.1468 - return;
23.1469 - }
23.1470 -
23.1471 - bool mustComputeReference;
23.1472 - if (i >= type->parameters()->length()) {
23.1473 - // Special handling for natives. Arguments past the formal must
23.1474 - // always have references computed. However, arrays are already
23.1475 - // references for natives.
23.1476 - assert(type->isNative() && type->isNativeVariadic());
23.1477 - mustComputeReference = !given->isReference() && !given->isArray();
23.1478 - } else {
23.1479 - Local<Type> actual(zone_, type->parameterAt(i));
23.1480 -
23.1481 - if (expression->isIndexExpression()) {
23.1482 - // Disabled until we can make it work.
23.1483 -#if 0
23.1484 - if (actual->isArray()) {
23.1485 - // We special case the ability to pass x[y] into x[], which
23.1486 - // creates an array slice. We only do this if we know the
23.1487 - // assignment would otherwise not type-check.
23.1488 - IndexExpression *index = expression->toIndexExpression();
23.1489 - if (index->left()->type()->levels() == actual->levels())
23.1490 - given = index->left()->type();
23.1491 - } else
23.1492 -#endif
23.1493 - if (actual->isReference()) {
23.1494 - cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
23.1495 - return;
23.1496 - }
23.1497 - }
23.1498 -
23.1499 - if (!typeCheckParameter(expression, given, actual))
23.1500 - return;
23.1501 - mustComputeReference = actual->isReference() && !given->isReference();
23.1502 - }
23.1503 -
23.1504 - // If the actual is a reference, and the given is not, we'll need to
23.1505 - // compute a reference, which may be allocated on the stack.
23.1506 - if (mustComputeReference)
23.1507 - scope_->setUsesLifoHeap();
23.1508 - }
23.1509 -
23.1510 - node->setType(type->returnType());
23.1511 -}
23.1512 -
23.1513 -void
23.1514 -SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
23.1515 -{
23.1516 - if (other.returns() < status().returns())
23.1517 - return;
23.1518 -
23.1519 - if (other.terminates())
23.1520 - terminate(other.returns());
23.1521 - else
23.1522 - returns(other.returns());
23.1523 -}
23.1524 -
23.1525 -void
23.1526 -SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
23.1527 -{
23.1528 - // If both sides terminate in a return, we consider this a return as well.
23.1529 - if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
23.1530 - terminate(Returns_Always);
23.1531 - return;
23.1532 - }
23.1533 -
23.1534 - ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
23.1535 - ? Returns_Never
23.1536 - : Returns_Sometimes;
23.1537 -
23.1538 - if (left.terminates() && right.terminates())
23.1539 - terminate(status);
23.1540 - else
23.1541 - returns(status);
23.1542 -}
23.1543 -
23.1544 -void
23.1545 -SemanticAnalysis::visit(IfStatement *node)
23.1546 -{
23.1547 - Local<Type> type(zone_, visitForLoad(node->condition()));
23.1548 - if (!type)
23.1549 - return;
23.1550 -
23.1551 - if (!canTest(node, type))
23.1552 - return;
23.1553 -
23.1554 - ControlStatus trueBranch = visitForControl(node->ifTrue());
23.1555 - ControlStatus falseBranch = ControlStatus(false, Returns_Never);
23.1556 -
23.1557 - if (node->ifFalse())
23.1558 - falseBranch = visitForControl(node->ifFalse());
23.1559 -
23.1560 - control_->merge(trueBranch, falseBranch);
23.1561 -}
23.1562 -
23.1563 -void
23.1564 -SemanticAnalysis::visit(IndexExpression *node)
23.1565 -{
23.1566 - Local<Type> left(zone_, visitForLoad(node->left()));
23.1567 - Local<Type> right(zone_, visitForLoad(node->right()));
23.1568 -
23.1569 - if (!left || !right)
23.1570 - return;
23.1571 -
23.1572 - if (!right->isInt32() && !right->isEnum()) {
23.1573 - cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
23.1574 - return;
23.1575 - }
23.1576 - if (!left->isArray()) {
23.1577 - cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
23.1578 - return;
23.1579 - }
23.1580 -
23.1581 - // Note: char arrays are automatically up-casted to return an int32.
23.1582 - if (left->isCharArray())
23.1583 - node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
23.1584 - else
23.1585 - node->setType(left->contained());
23.1586 -}
23.1587 -
23.1588 -void
23.1589 -SemanticAnalysis::visit(FieldExpression *node)
23.1590 -{
23.1591 - Local<Type> left(zone_, visitForLoad(node->left()));
23.1592 - if (!left)
23.1593 - return;
23.1594 -
23.1595 - if (!left->isStruct()) {
23.1596 - cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
23.1597 - GetTypeName(left));
23.1598 - return;
23.1599 - }
23.1600 -
23.1601 - Local<String> field(zone_, node->field());
23.1602 -
23.1603 - unsigned offset;
23.1604 - Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
23.1605 - if (!desc) {
23.1606 - cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
23.1607 - GetTypeName(left));
23.1608 - return;
23.1609 - }
23.1610 -
23.1611 - node->setFieldIndex(offset);
23.1612 - node->setType(desc->type());
23.1613 -}
23.1614 -
23.1615 -void
23.1616 -SemanticAnalysis::visit(EnumStatement *node)
23.1617 -{
23.1618 - Local<String> name(zone_, node->name());
23.1619 - Local<Type> type(zone_);
23.1620 - if (name)
23.1621 - type = zone_->types()->newEnum(name);
23.1622 - else
23.1623 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
23.1624 -
23.1625 - if (!type)
23.1626 - return;
23.1627 -
23.1628 - if (node->decl())
23.1629 - node->decl()->setType(type);
23.1630 -
23.1631 - int value = 0;
23.1632 - for (size_t i = 0; i < node->entries()->length(); i++) {
23.1633 - EnumStatement::Entry &entry = node->entries()->at(i);
23.1634 -
23.1635 - BoxedPrimitive box = BoxedPrimitive::Int(value);
23.1636 - if (entry.expr) {
23.1637 - entry.expr->accept(this);
23.1638 - if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
23.1639 - cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
23.1640 - return;
23.1641 - }
23.1642 -
23.1643 - assert(box.type() == PrimitiveType_Int32);
23.1644 - value = box.toInt();
23.1645 - }
23.1646 -
23.1647 -#if 0
23.1648 - entry.name->set(type, box);
23.1649 -#endif
23.1650 - value++;
23.1651 - }
23.1652 -}
23.1653 -
23.1654 -static int
23.1655 -SortCaseIntValues(const void *p1, const void *p2)
23.1656 -{
23.1657 - CaseValue *v1 = (CaseValue *)p1;
23.1658 - CaseValue *v2 = (CaseValue *)p2;
23.1659 -
23.1660 - return v1->box.toInt() - v2->box.toInt();
23.1661 -}
23.1662 -
23.1663 -void
23.1664 -SemanticAnalysis::visit(SwitchStatement *node)
23.1665 -{
23.1666 - Local<Type> caseType(zone_, visitForLoad(node->expression()));
23.1667 - if (!caseType)
23.1668 - return;
23.1669 -
23.1670 - if (!caseType->isEnum() && !caseType->isInt32()) {
23.1671 - cc_.reportError(node->pos(), Message_CaseMustBeInteger);
23.1672 - return;
23.1673 - }
23.1674 -
23.1675 - PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
23.1676 - ControlStatus status = ControlStatus(false, Returns_Never);
23.1677 -
23.1678 - Local<Type> check(zone_);
23.1679 - for (size_t i = 0; i < node->cases()->length(); i++) {
23.1680 - Case *c = node->cases()->at(i);
23.1681 -
23.1682 - check = visitForLoad(c->expression());
23.1683 - if (!check)
23.1684 - return;
23.1685 -
23.1686 - if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
23.1687 - return;
23.1688 -
23.1689 - CaseValue v(i);
23.1690 - if (!EvaluateForConstant(c->expression(), &v.box)) {
23.1691 - cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
23.1692 - return;
23.1693 - }
23.1694 - if (!values->append(v))
23.1695 - return;
23.1696 -
23.1697 - if (c->others()) {
23.1698 - for (size_t j = 0; j < c->others()->length(); j++) {
23.1699 - Expression *expr = c->others()->at(j);
23.1700 - check = visitForLoad(expr);
23.1701 - if (!check)
23.1702 - return;
23.1703 -
23.1704 - if (!typeCheckAssignment(expr->pos(), check, caseType, false))
23.1705 - return;
23.1706 -
23.1707 - CaseValue v(i);
23.1708 - if (!EvaluateForConstant(expr, &v.box)) {
23.1709 - cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
23.1710 - return;
23.1711 - }
23.1712 - if (!values->append(v))
23.1713 - return;
23.1714 - }
23.1715 - }
23.1716 -
23.1717 - ControlStatus latest = visitForControl(c->statement());
23.1718 -
23.1719 - if (i != 0)
23.1720 - control_->merge(status, latest);
23.1721 -
23.1722 - status = latest;
23.1723 - }
23.1724 -
23.1725 - if (node->defaultCase()) {
23.1726 - ControlStatus latest = visitForControl(node->defaultCase());
23.1727 -
23.1728 - if (node->cases()->length()) {
23.1729 - // If we had any other cases, we must merge.
23.1730 - control_->merge(status, latest);
23.1731 - } else {
23.1732 - // Otherwise, control-flow always flows through here.
23.1733 - control_->inherit(latest);
23.1734 - }
23.1735 - } else if (node->cases()->length()) {
23.1736 - control_->merge(status, ControlStatus(false, Returns_Never));
23.1737 - }
23.1738 -
23.1739 - if (values->length() > 1) {
23.1740 - qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
23.1741 -
23.1742 - for (size_t i = 1; i < values->length(); i++) {
23.1743 - CaseValue &prev = values->at(i - 1);
23.1744 - CaseValue &cur = values->at(i);
23.1745 - if (prev.box.toInt() == cur.box.toInt()) {
23.1746 - cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
23.1747 - return;
23.1748 - }
23.1749 - }
23.1750 - }
23.1751 -
23.1752 - node->setCaseValueList(values);
23.1753 -}
23.1754 -
23.1755 -void
23.1756 -SemanticAnalysis::visit(StructureStatement *node)
23.1757 -{
23.1758 -#if 0
23.1759 - // If this node already has a type, it was pre-analyzed, so skip it.
23.1760 - if (node->decl()->type())
23.1761 - return;
23.1762 -
23.1763 - FieldList *fields = node->fields();
23.1764 - Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
23.1765 - if (!desctable)
23.1766 - return;
23.1767 -
23.1768 - Vector<unsigned> composedList;
23.1769 - StructureBufferBuilder builder;
23.1770 -
23.1771 - Local<Type> type(zone_);
23.1772 - Local<String> name(zone_);
23.1773 - Local<Descriptor> desc(zone_);
23.1774 - for (size_t i = 0; i < fields->length(); i++) {
23.1775 - StructureStatement::Field *field = fields->at(i);
23.1776 -
23.1777 - type = bindType(field->pos(), field->type());
23.1778 - if (!type)
23.1779 - return;
23.1780 -
23.1781 - if (field->dimensions()) {
23.1782 - type = buildArrayType(type, field->dimensions(), false);
23.1783 - if (!type)
23.1784 - return;
23.1785 -
23.1786 - if (!ArrayMap::Attach(zone_, type))
23.1787 - return;
23.1788 - }
23.1789 -
23.1790 - if (IsScalarString(type)) {
23.1791 - cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
23.1792 - return;
23.1793 - }
23.1794 -
23.1795 - unsigned offset;
23.1796 - if (!builder.add(type, &offset))
23.1797 - return;
23.1798 -
23.1799 - name = field->name();
23.1800 - desc = Descriptor::New(zone_, name, type, offset);
23.1801 - if (!desc)
23.1802 - return;
23.1803 -
23.1804 - desctable->set(zone_, i, desc);
23.1805 -
23.1806 - if (type->isStruct() || type->isArray()) {
23.1807 - if (!composedList.append(i))
23.1808 - return;
23.1809 - }
23.1810 - }
23.1811 -
23.1812 - Local<FixedArray> composed(zone_);
23.1813 - if (composedList.length()) {
23.1814 - composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
23.1815 - if (!composed)
23.1816 - return;
23.1817 -
23.1818 - for (unsigned i = 0; i < composedList.length(); i++)
23.1819 - composed->set(zone_, i, desctable->at(i));
23.1820 - }
23.1821 -
23.1822 - Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
23.1823 - if (!map)
23.1824 - return;
23.1825 -
23.1826 - name = node->decl()->name();
23.1827 - type = zone_->types()->newStruct(name, desctable, map);
23.1828 - if (!type)
23.1829 - return;
23.1830 -
23.1831 - map->setType(type);
23.1832 - node->decl()->setType(type);
23.1833 -#endif
23.1834 -}
23.1835 -
23.1836 -void
23.1837 -SemanticAnalysis::visit(StringLiteral *node)
23.1838 -{
23.1839 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
23.1840 - if (!type)
23.1841 - return;
23.1842 -
23.1843 - type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
23.1844 - if (!type)
23.1845 - return;
23.1846 -
23.1847 - node->setType(type);
23.1848 -}
23.1849 -
23.1850 -void
23.1851 -SemanticAnalysis::visit(FloatLiteral *node)
23.1852 -{
23.1853 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
23.1854 - if (!type)
23.1855 - return;
23.1856 -
23.1857 - node->setType(type);
23.1858 -}
23.1859 -
23.1860 -void
23.1861 -SemanticAnalysis::visit(BreakStatement *node)
23.1862 -{
23.1863 - if (!loop_) {
23.1864 - cc_.reportError(node->pos(), Message_BreakOutsideLoop);
23.1865 - return;
23.1866 - }
23.1867 -
23.1868 - // Note: ignore breaks that occur in unreachable control-flow.
23.1869 - if (!control_->status().terminates())
23.1870 - loop_->addBreak();
23.1871 -
23.1872 - control_->terminate(Returns_Never);
23.1873 -}
23.1874 -
23.1875 -void
23.1876 -SemanticAnalysis::visit(ContinueStatement *node)
23.1877 -{
23.1878 - if (!loop_) {
23.1879 - cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
23.1880 - return;
23.1881 - }
23.1882 -
23.1883 - // Note: ignore continues that occur in unreachable control-flow.
23.1884 - if (!control_->status().terminates())
23.1885 - loop_->addContinue();
23.1886 -
23.1887 - control_->terminate(Returns_Never);
23.1888 -}
23.1889 -
23.1890 -void
23.1891 -SemanticAnalysis::visit(ArrayLiteral *node)
23.1892 -{
23.1893 - // We should never visit this.
23.1894 - cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
23.1895 -}
23.1896 -
23.1897 -void
23.1898 -SemanticAnalysis::visit(ImportStatement *node)
23.1899 -{
23.1900 -}
23.1901 -
23.1902 +/* vim: set ts=4 sw=4 tw=99 et:
23.1903 + *
23.1904 + * Copyright (C) 2012 David Anderson
23.1905 + *
23.1906 + * This file is part of JITCraft.
23.1907 + *
23.1908 + * JITCraft is free software: you can redistribute it and/or modify it under
23.1909 + * the terms of the GNU General Public License as published by the Free
23.1910 + * Software Foundation, either version 3 of the License, or (at your option)
23.1911 + * any later version.
23.1912 + *
23.1913 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
23.1914 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23.1915 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
23.1916 + *
23.1917 + * You should have received a copy of the GNU General Public License along with
23.1918 + * JITCraft. If not, see http://www.gnu.org/licenses/.
23.1919 + */
23.1920 +#include <string.h>
23.1921 +#include "SemanticAnalysis.h"
23.1922 +#include "../Types.h"
23.1923 +#include "../Zone.h"
23.1924 +#include "../TypeManager.h"
23.1925 +#include "../Strings.h"
23.1926 +#include "../Box.h"
23.1927 +#include "../Array.h"
23.1928 +#include "../Heap-inl.h"
23.1929 +#include "Scopes.h"
23.1930 +#include "NameBinding.h"
23.1931 +
23.1932 +using namespace ke;
23.1933 +
23.1934 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
23.1935 + : zone_(zone),
23.1936 + cc_(cc),
23.1937 + tree_(tree),
23.1938 + scope_(NULL),
23.1939 + loop_(NULL)
23.1940 +{
23.1941 +}
23.1942 +
23.1943 +bool
23.1944 +SemanticAnalysis::analyze()
23.1945 +{
23.1946 + assert(false);
23.1947 + return false;
23.1948 +}
23.1949 +
23.1950 +
23.1951 +#if 0
23.1952 +
23.1953 +static inline bool
23.1954 +IsPrimitiveType(Type *type, PrimitiveType primitive)
23.1955 +{
23.1956 + if (!type)
23.1957 + return false;
23.1958 +
23.1959 + if (!type->isPrimitive())
23.1960 + return false;
23.1961 +
23.1962 + return primitive == type->primitive();
23.1963 +}
23.1964 +
23.1965 +static inline bool
23.1966 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
23.1967 + BoxedPrimitive *out)
23.1968 +{
23.1969 + switch (kind) {
23.1970 + case TOK_PLUS:
23.1971 + *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
23.1972 + return true;
23.1973 +
23.1974 + case TOK_SHL:
23.1975 + *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
23.1976 + return true;
23.1977 +
23.1978 + default:
23.1979 + return false;
23.1980 + }
23.1981 +}
23.1982 +
23.1983 +static inline bool
23.1984 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
23.1985 +{
23.1986 + switch (kind) {
23.1987 + case TOK_MINUS:
23.1988 + *out = BoxedPrimitive::Int(-inner.toInt());
23.1989 + return true;
23.1990 +
23.1991 + default:
23.1992 + return false;
23.1993 + }
23.1994 +}
23.1995 +
23.1996 +static bool
23.1997 +EvaluateForConstant(Expression *expression, BoxedPrimitive *out)
23.1998 +{
23.1999 + switch (expression->kind()) {
23.2000 + case AstNode::kBinaryExpression:
23.2001 + {
23.2002 + BoxedPrimitive left;
23.2003 + BoxedPrimitive right;
23.2004 + BinaryExpression *b = expression->toBinaryExpression();
23.2005 + if (!EvaluateForConstant(b->left(), &left) ||
23.2006 + !EvaluateForConstant(b->right(), &right))
23.2007 + {
23.2008 + return false;
23.2009 + }
23.2010 + return EvaluateBinaryOperation(b->token(), left, right, out);
23.2011 + }
23.2012 +
23.2013 + case AstNode::kUnaryExpression:
23.2014 + {
23.2015 + BoxedPrimitive inner;
23.2016 + UnaryExpression *u = expression->toUnaryExpression();
23.2017 + if (!EvaluateForConstant(u->expression(), &inner))
23.2018 + return false;
23.2019 + return EvaluateUnaryOperation(u->token(), inner, out);
23.2020 + }
23.2021 +
23.2022 + case AstNode::kNameProxy:
23.2023 + {
23.2024 + NameProxy *proxy = expression->toNameProxy();
23.2025 + if (proxy->binding()->kind() != BoundName::CONSTANT)
23.2026 + return false;
23.2027 +
23.2028 + NamedConstant *c = proxy->binding()->toNamedConstant();
23.2029 + if (!IsPrimitiveType(c->type(), PrimitiveType_Int32))
23.2030 + return false;
23.2031 +
23.2032 + *out = c->value();
23.2033 + return true;
23.2034 + }
23.2035 +
23.2036 + case AstNode::kBooleanLiteral:
23.2037 + *out = BoxedPrimitive::Int(expression->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
23.2038 + return true;
23.2039 +
23.2040 + case AstNode::kIntegerLiteral:
23.2041 + *out = BoxedPrimitive::Int(expression->toIntegerLiteral()->value());
23.2042 + return true;
23.2043 +
23.2044 + default:
23.2045 + return false;
23.2046 + }
23.2047 +}
23.2048 +
23.2049 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree)
23.2050 + : zone_(zone),
23.2051 + cc_(cc),
23.2052 + tree_(tree),
23.2053 + scope_(NULL),
23.2054 + loop_(NULL)
23.2055 +{
23.2056 +}
23.2057 +
23.2058 +bool
23.2059 +SemanticAnalysis::analyze()
23.2060 +{
23.2061 + if (cc_.failures())
23.2062 + return false;
23.2063 +
23.2064 + scope_ = tree_->globalScope();
23.2065 + assert(scope_->kind() == Scope::GLOBAL);
23.2066 +
23.2067 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
23.2068 + Statement *statement = tree_->statements()->at(i);
23.2069 + if (statement->isFunctionStatement()) {
23.2070 + FunctionStatement *funstmt = statement->toFunctionStatement();
23.2071 + if (!preanalyze(funstmt))
23.2072 + return false;
23.2073 + } else if (statement->isEnumStatement()) {
23.2074 + EnumStatement *enumstmt = statement->toEnumStatement();
23.2075 +
23.2076 + // We pre-fill global enum types, since they may occur in function
23.2077 + // signatures. This should probably be somewhere else...
23.2078 + enumstmt->accept(this);
23.2079 + } else if (statement->isStructureStatement()) {
23.2080 + StructureStatement *node = statement->toStructureStatement();
23.2081 + node->accept(this);
23.2082 + if (!node->decl()->type())
23.2083 + return false;
23.2084 + } else if (statement->isFunctionTypeStatement()) {
23.2085 + FunctionTypeStatement *node = statement->toFunctionTypeStatement();
23.2086 + node->accept(this);
23.2087 + if (!node->decl()->type())
23.2088 + return false;
23.2089 + }
23.2090 + }
23.2091 +
23.2092 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
23.2093 + Statement *statement = tree_->statements()->at(i);
23.2094 +
23.2095 + // We can't double-process these. Maybe put this check somewhere else.
23.2096 + if (statement->isEnumStatement())
23.2097 + continue;
23.2098 +
23.2099 + statement->accept(this);
23.2100 + }
23.2101 +
23.2102 + if (!determineLiveFunctions())
23.2103 + return false;
23.2104 +
23.2105 + return !cc_.failures();
23.2106 +}
23.2107 +
23.2108 +bool
23.2109 +SemanticAnalysis::determineLiveFunctions()
23.2110 +{
23.2111 + Vector<NamedFunction *> worklist;
23.2112 +
23.2113 + // Add the root set.
23.2114 + for (size_t i = 0; i < tree_->statements()->length(); i++) {
23.2115 + Statement *statement = tree_->statements()->at(i);
23.2116 + if (!statement->isFunctionStatement())
23.2117 + continue;
23.2118 +
23.2119 + FunctionStatement *stmt = statement->toFunctionStatement();
23.2120 + NamedFunction *fun = stmt->fun();
23.2121 + if (!fun->used())
23.2122 + continue;
23.2123 +
23.2124 + for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
23.2125 + NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
23.2126 +
23.2127 + // Names in these lists are always unused, however, we mark them
23.2128 + // as used while inserting into the work queue, to avoid double-
23.2129 + // insertion.
23.2130 + if (name->used())
23.2131 + continue;
23.2132 +
23.2133 + if (!worklist.append(name))
23.2134 + return false;
23.2135 +
23.2136 + name->setUsed();
23.2137 + }
23.2138 + }
23.2139 +
23.2140 + while (!worklist.empty()) {
23.2141 + NamedFunction *fun = worklist.popCopy();
23.2142 +
23.2143 + for (size_t i = 0; i < fun->usedGlobals()->length(); i++) {
23.2144 + NamedFunction *name = fun->usedGlobals()->at(i)->toNamedFunction();
23.2145 + if (name->used())
23.2146 + continue;
23.2147 + if (!worklist.append(name))
23.2148 + return false;
23.2149 + name->setUsed();
23.2150 + }
23.2151 + }
23.2152 +
23.2153 + return true;
23.2154 +}
23.2155 +
23.2156 +Type *
23.2157 +SemanticAnalysis::bindType(const SourcePosition &pos, BoundName *name)
23.2158 +{
23.2159 + if (!name)
23.2160 + return zone_->types()->getPrimitive(PrimitiveType_Int32);
23.2161 +
23.2162 + if (name->kind() == BoundName::UNBOUND) {
23.2163 + cc_.reportError(pos, Message_TypeNotFound, name->name()->chars());
23.2164 + return NULL;
23.2165 + }
23.2166 +
23.2167 + if (name->kind() != BoundName::TYPE) {
23.2168 + cc_.reportError(pos, Message_IdentifierIsNotAType, name->name()->chars());
23.2169 + return NULL;
23.2170 + }
23.2171 +
23.2172 + if (!name->type())
23.2173 + return NULL;
23.2174 +
23.2175 + return name->type();
23.2176 +}
23.2177 +
23.2178 +Type *
23.2179 +SemanticAnalysis::visitAndApplyType(Expression *expression)
23.2180 +{
23.2181 + expression->accept(this);
23.2182 + return expression->type();
23.2183 +}
23.2184 +
23.2185 +Type *
23.2186 +SemanticAnalysis::visitForLoad(Expression *expression)
23.2187 +{
23.2188 + Local<Type> type(zone_, visitAndApplyType(expression));
23.2189 + if (!type)
23.2190 + return NULL;
23.2191 +
23.2192 + if (type->isReference()) {
23.2193 + expression->setType(type->contained());
23.2194 + } else if (expression->isCallExpression()) {
23.2195 + if (type->isVoid()) {
23.2196 + CallExpression *call = expression->toCallExpression();
23.2197 + cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
23.2198 + return NULL;
23.2199 + }
23.2200 + }
23.2201 +
23.2202 + return expression->type();
23.2203 +}
23.2204 +
23.2205 +void
23.2206 +SemanticAnalysis::unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type)
23.2207 +{
23.2208 + const char *op = TokenNames[token];
23.2209 + const char *name = GetTypeName(type);
23.2210 +
23.2211 + cc_.reportError(node->pos(), Message_UnaryTypeError, op, name);
23.2212 +}
23.2213 +
23.2214 +void
23.2215 +SemanticAnalysis::binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
23.2216 +{
23.2217 + const char *op = TokenNames[token];
23.2218 + const char *leftName = GetTypeName(left);
23.2219 + const char *rightName = GetTypeName(right);
23.2220 +
23.2221 + cc_.reportError(node->pos(), Message_BinaryTypeError, op, leftName, rightName);
23.2222 +}
23.2223 +
23.2224 +Type *
23.2225 +SemanticAnalysis::typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right)
23.2226 +{
23.2227 + if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
23.2228 + (token >= TOK_ASSIGN_ADD && token <= TOK_ASSIGN_DIV))
23.2229 + {
23.2230 + // If either side is a float, the other side must be a float or int.
23.2231 + if (left->isFloat() || right->isFloat()) {
23.2232 + Type *floatType = left->isFloat() ? left : right;
23.2233 + Type *other = left->isFloat() ? right : left;
23.2234 + if (other->isFloat() || other->isInt32())
23.2235 + return floatType;
23.2236 + }
23.2237 + }
23.2238 +
23.2239 + if (token == TOK_OR || token == TOK_AND) {
23.2240 + if (!canTest(node, left) || !canTest(node, right))
23.2241 + return NULL;
23.2242 + return zone_->types()->getPrimitive(PrimitiveType_Bool);
23.2243 + }
23.2244 +
23.2245 + if (token >= TOK_EQUALS && token <= TOK_GE) {
23.2246 + if ((left->isFloat() || left->isInt32()) &&
23.2247 + (right->isFloat() || right->isInt32()))
23.2248 + {
23.2249 + return zone_->types()->getPrimitive(PrimitiveType_Bool);
23.2250 + }
23.2251 + binaryTypeError(node, token, left, right);
23.2252 + return NULL;
23.2253 + }
23.2254 +
23.2255 + if (!left->isInt32() || !right->isInt32()) {
23.2256 + binaryTypeError(node, token, left, right);
23.2257 + return NULL;
23.2258 + }
23.2259 +
23.2260 + return left;
23.2261 +}
23.2262 +
23.2263 +bool
23.2264 +SemanticAnalysis::canTest(AstNode *node, Handle<Type> type)
23.2265 +{
23.2266 + if (!type->isPrimitive() && !type->isEnum()) {
23.2267 + cc_.reportError(node->pos(), Message_ArrayIsNotBoolean);
23.2268 + return false;
23.2269 + }
23.2270 + return true;
23.2271 +}
23.2272 +
23.2273 +Type *
23.2274 +SemanticAnalysis::visitForLValue(Expression *expression)
23.2275 +{
23.2276 + if (expression->isIndexExpression()) {
23.2277 + Type *type = visitAndApplyType(expression);
23.2278 + if (!type)
23.2279 + return NULL;
23.2280 +
23.2281 + // if (type->isConst()) {
23.2282 + // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
23.2283 + // return NULL;
23.2284 + // }
23.2285 +
23.2286 + return type;
23.2287 + }
23.2288 +
23.2289 + if (expression->isFieldExpression()) {
23.2290 + Type *type = visitAndApplyType(expression);
23.2291 + if (!type)
23.2292 + return NULL;
23.2293 +
23.2294 + // if (expression->toFieldExpression()->left()->type()->isConst()) {
23.2295 + // cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
23.2296 + // return NULL;
23.2297 + // }
23.2298 +
23.2299 + return type;
23.2300 + }
23.2301 +
23.2302 + if (!expression->isNameProxy()) {
23.2303 + cc_.reportError(expression->pos(), Message_ExpectedLValue);
23.2304 + return NULL;
23.2305 + }
23.2306 +
23.2307 + NameProxy *proxy = expression->toNameProxy();
23.2308 + if (!proxy->binding()->kind() == BoundName::VARIABLE) {
23.2309 + cc_.reportError(expression->pos(), Message_ExpectedLValue);
23.2310 + return NULL;
23.2311 + }
23.2312 +
23.2313 + Variable *var = proxy->binding()->toVariable();
23.2314 + if (!var->type())
23.2315 + return NULL;
23.2316 +
23.2317 + if (var->type()->isReference()) {
23.2318 + if (var->type()->isConst()) {
23.2319 + cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
23.2320 + return NULL;
23.2321 + }
23.2322 + return var->type()->contained();
23.2323 + }
23.2324 + return var->type();
23.2325 +}
23.2326 +
23.2327 +SemanticAnalysis::ControlStatus
23.2328 +SemanticAnalysis::visitForControl(Statement *statement)
23.2329 +{
23.2330 + ControlScope scope(&control_);
23.2331 + statement->accept(this);
23.2332 + return scope.status();
23.2333 +}
23.2334 +
23.2335 +void
23.2336 +SemanticAnalysis::visit(NameProxy *name)
23.2337 +{
23.2338 + BoundName *binding = name->binding();
23.2339 +
23.2340 + if (binding->scope()->kind() == Scope::GLOBAL) {
23.2341 + if (!function_ || function_->isPublic()) {
23.2342 + // Whatever we're referencing must be kept alive no matter what.
23.2343 + // As such, we simply mark it used, and don't do anything special.
23.2344 + binding->setUsed();
23.2345 + } else if (!binding->used() && binding->kind() == BoundName::FUNCTION) {
23.2346 + // Otherwise, we're inside a normal stock or function. Since we
23.2347 + // don't really know if we've been used yet, we shouldn't
23.2348 + // prematurely references as alive. Instead, we keep a list of
23.2349 + // which names have been used, so we can mark them later if needed.
23.2350 + //
23.2351 + // Note that we skip this step if the binding is already in the
23.2352 + // root set.
23.2353 + if (!function_->addUsedGlobal(binding))
23.2354 + return;
23.2355 + }
23.2356 + }
23.2357 +
23.2358 + name->setType(binding->type());
23.2359 +}
23.2360 +
23.2361 +void
23.2362 +SemanticAnalysis::visit(Assignment *node)
23.2363 +{
23.2364 + Local<Type> exprType(zone_, visitForLoad(node->expression()));
23.2365 + if (!exprType)
23.2366 + return ;
23.2367 +
23.2368 + Local<Type> type(zone_, visitForLValue(node->lvalue()));
23.2369 + if (!type)
23.2370 + return;
23.2371 +
23.2372 + if (node->token() != TOK_ASSIGN) {
23.2373 + if (!typeCheckBinary(node, node->token(), type, exprType))
23.2374 + return;
23.2375 + }
23.2376 +
23.2377 + if (!typeCheckAssignment(node->pos(), exprType, type, true))
23.2378 + return;
23.2379 +
23.2380 + node->setType(type);
23.2381 +}
23.2382 +
23.2383 +void
23.2384 +SemanticAnalysis::visit(IncDecExpression *node)
23.2385 +{
23.2386 + Local<Type> type(zone_, visitForLValue(node->expression()));
23.2387 + if (!type)
23.2388 + return;
23.2389 +
23.2390 + assert(!type->isReference());
23.2391 +
23.2392 + if (!type->isInt32() && !type->isFloat()) {
23.2393 + unaryTypeError(node, node->token(), type);
23.2394 + return;
23.2395 + }
23.2396 +
23.2397 + node->setType(type);
23.2398 +}
23.2399 +
23.2400 +void
23.2401 +SemanticAnalysis::visit(UnaryExpression *node)
23.2402 +{
23.2403 + Local<Type> type(zone_, visitForLoad(node->expression()));
23.2404 + if (!type)
23.2405 + return;
23.2406 +
23.2407 + switch (node->token())
23.2408 + {
23.2409 + case TOK_NOT:
23.2410 + if (!canTest(node->expression(), type))
23.2411 + return;
23.2412 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
23.2413 + if (!type)
23.2414 + return;
23.2415 + node->setType(type);
23.2416 + break;
23.2417 +
23.2418 + case TOK_MINUS:
23.2419 + if (!type->isFloat() && !type->isInt32()) {
23.2420 + unaryTypeError(node, node->token(), type);
23.2421 + return;
23.2422 + }
23.2423 + node->setType(type);
23.2424 + break;
23.2425 +
23.2426 + case TOK_LABEL:
23.2427 + {
23.2428 + Local<Type> to(zone_, bindType(node->pos(), node->type()));
23.2429 + if (!to)
23.2430 + return;
23.2431 +
23.2432 + if ((!type->isFloat() && !type->isInt32OrEnum()) ||
23.2433 + (!to->isFloat() && !to->isInt32OrEnum()))
23.2434 + {
23.2435 + unaryTypeError(node, node->token(), type);
23.2436 + return;
23.2437 + }
23.2438 +
23.2439 + node->setType(to);
23.2440 + break;
23.2441 + }
23.2442 +
23.2443 + case TOK_SIZEOF:
23.2444 + {
23.2445 + if (!type->isArray()) {
23.2446 + cc_.reportError(node->pos(), Message_SizeofNeedsArray);
23.2447 + return;
23.2448 + }
23.2449 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
23.2450 + break;
23.2451 + }
23.2452 +
23.2453 + default:
23.2454 + assert(node->token() == TOK_TILDE);
23.2455 + if (!type->isInt32()) {
23.2456 + unaryTypeError(node, node->token(), type);
23.2457 + return;
23.2458 + }
23.2459 + node->setType(type);
23.2460 + break;
23.2461 + }
23.2462 +}
23.2463 +
23.2464 +void
23.2465 +SemanticAnalysis::visit(TernaryExpression *node)
23.2466 +{
23.2467 + Local<Type> type(zone_, visitForLoad(node->condition()));
23.2468 + if (!type)
23.2469 + return;
23.2470 +
23.2471 + if (!canTest(node->condition(), type))
23.2472 + return;
23.2473 +
23.2474 + Local<Type> left(zone_, visitForLoad(node->left()));
23.2475 + Local<Type> right(zone_, visitForLoad(node->right()));
23.2476 + if (!left || !right)
23.2477 + return;
23.2478 +
23.2479 + if (left != right) {
23.2480 + binaryTypeError(node, TOK_QMARK, left, right);
23.2481 + return;
23.2482 + }
23.2483 +}
23.2484 +
23.2485 +void
23.2486 +SemanticAnalysis::visit(BinaryExpression *node)
23.2487 +{
23.2488 + Local<Type> left(zone_, visitForLoad(node->left()));
23.2489 + Local<Type> right(zone_, visitForLoad(node->right()));
23.2490 + if (!left || !right)
23.2491 + return;
23.2492 +
23.2493 + Local<Type> result(zone_, typeCheckBinary(node, node->token(), left, right));
23.2494 + if (!result)
23.2495 + return;
23.2496 +
23.2497 + node->setType(result);
23.2498 +}
23.2499 +
23.2500 +void
23.2501 +SemanticAnalysis::visit(ReturnStatement *node)
23.2502 +{
23.2503 + // Set this early, so if we error we don't get more errors.
23.2504 + control_->returns(Returns_Always);
23.2505 +
23.2506 + if (!node->expression()) {
23.2507 + if (!function_->type()->returnType()->isVoid())
23.2508 + cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
23.2509 + return;
23.2510 + }
23.2511 +
23.2512 + Local<Type> type(zone_, visitForLoad(node->expression()));
23.2513 + if (!type)
23.2514 + return;
23.2515 +
23.2516 + Local<Type> returnType(zone_, function_->type()->returnType());
23.2517 + if (!typeCheckAssignment(node->pos(), type, returnType, true))
23.2518 + return;
23.2519 +}
23.2520 +
23.2521 +void
23.2522 +SemanticAnalysis::visit(ForStatement *node)
23.2523 +{
23.2524 + LoopScope loop(&loop_);
23.2525 +
23.2526 + if (node->scope())
23.2527 + scope_ = node->scope();
23.2528 +
23.2529 + if (node->initialization())
23.2530 + node->initialization()->accept(this);
23.2531 +
23.2532 + if (node->condition()) {
23.2533 + Local<Type> type(zone_, visitForLoad(node->condition()));
23.2534 + if (!type || !canTest(node->condition(), type)) {
23.2535 + return;
23.2536 + }
23.2537 + }
23.2538 +
23.2539 + if (node->update())
23.2540 + node->update()->accept(this);
23.2541 +
23.2542 + ControlStatus status = visitForControl(node->body());
23.2543 +
23.2544 + // If there is a condition, we treat this like a while loop. Otherwise,
23.2545 + // join point is only reachable if the loop contains a break. The
23.2546 + // termination status doesn't tell us anything yet.
23.2547 + if (node->condition() || loop.breaks())
23.2548 + control_->merge(status, ControlStatus(false, Returns_Never));
23.2549 + else
23.2550 + control_->terminate(status.returns());
23.2551 +
23.2552 + if (node->scope())
23.2553 + scope_ = scope_->enclosing();
23.2554 +}
23.2555 +
23.2556 +void
23.2557 +SemanticAnalysis::visit(WhileStatement *node)
23.2558 +{
23.2559 + LoopScope loop(&loop_);
23.2560 +
23.2561 + Local<Type> type(zone_, visitForLoad(node->condition()));
23.2562 + if (!type || !canTest(node->condition(), type)) {
23.2563 + return;
23.2564 + }
23.2565 +
23.2566 + ControlStatus status = visitForControl(node->body());
23.2567 +
23.2568 + // Detect loops that will always have a fork in the control-flow graph.
23.2569 + // This will be a |while| loop, or a |do-while| loop whose body does
23.2570 + // not terminate.
23.2571 + //
23.2572 + // For now, we treat these as an |if| regardless of the direction the
23.2573 + // branch can take. That means the control-flow is always conditional.
23.2574 + if (node->token() == TOK_WHILE ||
23.2575 + !status.terminates() ||
23.2576 + loop.breaks())
23.2577 + {
23.2578 + control_->merge(status, ControlStatus(false, Returns_Never));
23.2579 + } else {
23.2580 + // At this point, we've got a do-while loop with a |return| or
23.2581 + // |continue|, meaning that the rest of the block is unreachable.
23.2582 + control_->terminate(status.returns());
23.2583 + }
23.2584 +}
23.2585 +
23.2586 +void
23.2587 +SemanticAnalysis::visit(BlockStatement *node)
23.2588 +{
23.2589 + if (node->scope())
23.2590 + scope_ = node->scope();
23.2591 + for (size_t i = 0; i < node->statements()->length(); i++) {
23.2592 + Statement *statement = node->statements()->at(i);
23.2593 + statement->accept(this);
23.2594 + }
23.2595 + if (node->scope())
23.2596 + scope_ = scope_->enclosing();
23.2597 +}
23.2598 +
23.2599 +static inline bool
23.2600 +IsScalarString(Type *type)
23.2601 +{
23.2602 + if (type->isPrimitive() && type->primitive() == PrimitiveType_Char)
23.2603 + return true;
23.2604 + if (type->isReference())
23.2605 + return IsScalarString(type->contained());
23.2606 + return false;
23.2607 +}
23.2608 +
23.2609 +static const int INFER_ARRAY_SIZE = 0;
23.2610 +static const int EVAL_ARRAY_SIZE = -1;
23.2611 +static const int DYNAMIC_ARRAY_SIZE = -2;
23.2612 +
23.2613 +bool
23.2614 +SemanticAnalysis::evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH])
23.2615 +{
23.2616 + bool hadEmptySize = false;
23.2617 +
23.2618 + for (size_t i = 0; i < exprs->length(); i++) {
23.2619 + Expression *expr = exprs->at(i);
23.2620 + if (!expr) {
23.2621 + dims[i] = INFER_ARRAY_SIZE;
23.2622 + hadEmptySize = true;
23.2623 + continue;
23.2624 + }
23.2625 +
23.2626 + BoxedPrimitive box;
23.2627 + if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
23.2628 + int size = box.toInt();
23.2629 + if (size <= 0) {
23.2630 + cc_.reportError(expr->pos(), Message_BadArraySize);
23.2631 + return false;
23.2632 + }
23.2633 +
23.2634 + dims[i] = size;
23.2635 + continue;
23.2636 + }
23.2637 +
23.2638 + Local<Type> exprType(zone_, visitForLoad(expr));
23.2639 + if (!exprType)
23.2640 + return false;
23.2641 +
23.2642 + if (!IsPrimitiveType(exprType, PrimitiveType_Int32)) {
23.2643 + cc_.reportError(expr->pos(), Message_ArrayDimensionNotInteger);
23.2644 + return false;
23.2645 + }
23.2646 +
23.2647 + if (hadEmptySize) {
23.2648 + cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
23.2649 + return false;
23.2650 + }
23.2651 +
23.2652 + dims[i] = EVAL_ARRAY_SIZE;
23.2653 + }
23.2654 +
23.2655 + return true;
23.2656 +}
23.2657 +
23.2658 +bool
23.2659 +SemanticAnalysis::inferFixedArrayLiteral(ArrayLiteral *literal, Handle<Type> contained,
23.2660 + int dims[MAX_ARRAY_DEPTH],
23.2661 + unsigned dimcount, unsigned level)
23.2662 +{
23.2663 + if (dims[level] == EVAL_ARRAY_SIZE) {
23.2664 + cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
23.2665 + return false;
23.2666 + }
23.2667 +
23.2668 + if (dims[level] == INFER_ARRAY_SIZE) {
23.2669 + // Strings always become dynamic arrays.
23.2670 + if (level != dimcount - 1 || !IsPrimitiveType(contained, PrimitiveType_Char))
23.2671 + dims[level] = literal->expressions()->length();
23.2672 + } else if (dims[level] == DYNAMIC_ARRAY_SIZE) {
23.2673 + cc_.reportError(literal->pos(), Message_CannotInitializeEvalArray);
23.2674 + return false;
23.2675 + } else {
23.2676 + if (literal->expressions()->length() != unsigned(dims[level])) {
23.2677 + cc_.reportError(literal->pos(), Message_ArrayDimensionSizeMismatch, level + 1);
23.2678 + return false;
23.2679 + }
23.2680 + }
23.2681 +
23.2682 + if (level == dimcount - 2 && IsPrimitiveType(contained, PrimitiveType_Char)) {
23.2683 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
23.2684 + Expression *expr = literal->expressions()->at(i);
23.2685 + if (!expr->isStringLiteral()) {
23.2686 + cc_.reportError(expr->pos(), Message_ExpectedStringLiteral);
23.2687 + return false;
23.2688 + }
23.2689 +
23.2690 + StringLiteral *lit = expr->toStringLiteral();
23.2691 + if (dims[level + 1] > 0 &&
23.2692 + unsigned(dims[level]) < lit->string()->length())
23.2693 + {
23.2694 + cc_.reportError(lit->pos(), Message_ArrayDimensionSizeMismatch, level + 2);
23.2695 + return false;
23.2696 + }
23.2697 + if (!visitAndApplyType(lit))
23.2698 + return false;
23.2699 + }
23.2700 + } else if (level == dimcount - 1) {
23.2701 + Local<Type> type(zone_);
23.2702 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
23.2703 + Expression *expr = literal->expressions()->at(i);
23.2704 + if (expr->isArrayLiteral()) {
23.2705 + cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
23.2706 + return false;
23.2707 + }
23.2708 +
23.2709 + if ((type = visitAndApplyType(expr)) == NULL)
23.2710 + return false;
23.2711 +
23.2712 + if (!typeCheckAssignment(expr->pos(), type, contained, true))
23.2713 + return false;
23.2714 + }
23.2715 + } else {
23.2716 + for (size_t i = 0; i < literal->expressions()->length(); i++) {
23.2717 + Expression *expr = literal->expressions()->at(i);
23.2718 + if (!expr->isArrayLiteral()) {
23.2719 + cc_.reportError(expr->pos(), Message_ArrayDimensionsMismatch);
23.2720 + return false;
23.2721 + }
23.2722 +
23.2723 + assert(expr->toArrayLiteral()->isFixed());
23.2724 +
23.2725 + if (!inferFixedArrayLiteral(expr->toArrayLiteral(),
23.2726 + contained,
23.2727 + dims,
23.2728 + dimcount,
23.2729 + level + 1))
23.2730 + {
23.2731 + return false;
23.2732 + }
23.2733 + }
23.2734 + }
23.2735 +
23.2736 + return true;
23.2737 +}
23.2738 +
23.2739 +void
23.2740 +SemanticAnalysis::visit(VariableDeclaration *node)
23.2741 +{
23.2742 + Local<Type> type(zone_, bindType(node->pos(), node->type()));
23.2743 + if (!type)
23.2744 + return;
23.2745 +
23.2746 +#if 0
23.2747 + if (node->postDimensions() || type->isArray()) {
23.2748 + // The type could be an array type, so sum the type and postDimensions
23.2749 + // together.
23.2750 + unsigned dimcount = node->postDimensions()->length();
23.2751 + if (type->isArray())
23.2752 + dimcount += type->levels();
23.2753 + if (dimcount > MAX_ARRAY_DEPTH) {
23.2754 + cc_.reportError(node->pos(), Message_MaximumArrayDepth);
23.2755 + return;
23.2756 + }
23.2757 +
23.2758 + // Take an initial guess at the array dimension sizes.
23.2759 + int dims[MAX_ARRAY_DEPTH];
23.2760 + if (!evaluateDimensions(node->postDimensions(), dims))
23.2761 + return;
23.2762 +
23.2763 + // Now add in the type's array dimensions.
23.2764 + Local<Type> contained(zone_, type);
23.2765 + for (size_t i = node->postDimensions()->length(); i < dimcount; i++) {
23.2766 + if (type->isFixedLength())
23.2767 + dims[i] = type->fixedLength();
23.2768 + else
23.2769 + dims[i] = DYNAMIC_ARRAY_SIZE;
23.2770 + contained = contained->contained();
23.2771 + }
23.2772 +
23.2773 + Expression *initializer = node->initialization();
23.2774 + if (initializer &&
23.2775 + initializer->isArrayLiteral() &&
23.2776 + initializer->toArrayLiteral()->isFixed())
23.2777 + {
23.2778 + // Fixed array initializers are special; we use them to infer any
23.2779 + // missing information in the original array. We do not evaluate
23.2780 + // the array initializer as an expression.
23.2781 + if (!inferFixedArrayLiteral(initializer->toArrayLiteral(),
23.2782 + contained,
23.2783 + dims,
23.2784 + dimcount,
23.2785 + 0))
23.2786 + {
23.2787 + return;
23.2788 + }
23.2789 + initializer = NULL;
23.2790 + }
23.2791 +
23.2792 + // We now have enough information to build the actual array type.
23.2793 + // Start from the original dimcount, not the one computed for
23.2794 + // initializers.
23.2795 + for (size_t i = node->postDimensions()->length() - 1;
23.2796 + i < node->postDimensions()->length();
23.2797 + i--)
23.2798 + {
23.2799 + int size = dims[i] > 0
23.2800 + ? dims[i]
23.2801 + : Type::DYNAMIC_ARRAY_SIZE;
23.2802 +
23.2803 + type = zone_->types()->newArray(type, size, false);
23.2804 + if (!type)
23.2805 + return;
23.2806 + }
23.2807 +
23.2808 + // Finally, if we had a non-fixed initializer, make sure it type
23.2809 + // checks.
23.2810 + if (initializer) {
23.2811 + Local<Type> right(zone_, visitForLoad(initializer));
23.2812 + if (!right)
23.2813 + return;
23.2814 +
23.2815 + if (!typeCheckAssignment(node->pos(), right, type, true))
23.2816 + return;
23.2817 + }
23.2818 + } else {
23.2819 + if (node->initialization()) {
23.2820 + Local<Type> right(zone_, visitForLoad(node->initialization()));
23.2821 + if (!right)
23.2822 + return;
23.2823 + if (!typeCheckAssignment(node->pos(), right, type, true))
23.2824 + return;
23.2825 + }
23.2826 +
23.2827 + if (type->isPrimitive() && type->primitive() == PrimitiveType_Char) {
23.2828 + cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.2829 + return;
23.2830 + }
23.2831 + }
23.2832 +#endif
23.2833 +
23.2834 +#if 0
23.2835 + // If this variable is stack allocated, we could use the LIFO heap
23.2836 + // to allocate it. If that's the case, make sure to reserve a slot
23.2837 + // so we can unwind the LIFO heap at the end of this scope.
23.2838 + if (!node->variable()->needsHeapAllocation()) {
23.2839 + if (type->isArray() || type->isStruct())
23.2840 + scope_->setUsesLifoHeap();
23.2841 + }
23.2842 +
23.2843 + node->variable()->setType(type);
23.2844 +#endif
23.2845 +}
23.2846 +
23.2847 +void
23.2848 +SemanticAnalysis::visit(IntegerLiteral *node)
23.2849 +{
23.2850 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
23.2851 +}
23.2852 +
23.2853 +void
23.2854 +SemanticAnalysis::visit(BooleanLiteral *node)
23.2855 +{
23.2856 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Bool));
23.2857 +}
23.2858 +
23.2859 +void
23.2860 +SemanticAnalysis::visit(ExpressionStatement *node)
23.2861 +{
23.2862 + visitAndApplyType(node->expression());
23.2863 +}
23.2864 +
23.2865 +Box *
23.2866 +SemanticAnalysis::evaluateDefaultParameter(Handle<Type> type, Parameter *parameter)
23.2867 +{
23.2868 + Local<Type> given(zone_, visitForLoad(parameter->initializer()));
23.2869 +
23.2870 + BoxedPrimitive prim;
23.2871 + if (EvaluateForConstant(parameter->initializer(), &prim)) {
23.2872 + if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
23.2873 + return NULL;
23.2874 +
23.2875 + if (prim.type() == PrimitiveType_Int32)
23.2876 + return Box::New(zone_, given, prim.toInt());
23.2877 + return Box::New(zone_, given, prim.toFloat());
23.2878 + } else if (parameter->initializer()->isStringLiteral()) {
23.2879 + StringLiteral *literal = parameter->initializer()->toStringLiteral();
23.2880 +
23.2881 + if (!typeCheckAssignment(parameter->initializer()->pos(), given, type, false))
23.2882 + return NULL;
23.2883 +
23.2884 + Local<ArrayMap> map(zone_, ArrayMap::Attach(zone_, given));
23.2885 + if (!map)
23.2886 + return NULL;
23.2887 +
23.2888 + Local<Array> array(zone_,
23.2889 + Array::NewString(zone_,
23.2890 + map,
23.2891 + literal->string()->raw(),
23.2892 + literal->string()->length(),
23.2893 + Heap::Tenure_Old));
23.2894 + if (!array)
23.2895 + return NULL;
23.2896 +
23.2897 + return Box::NewObj(zone_, given, array, Heap::Tenure_Old);
23.2898 + }
23.2899 +
23.2900 + cc_.reportError(parameter->initializer()->pos(), Message_MustBeConstant);
23.2901 + return NULL;
23.2902 +}
23.2903 +
23.2904 +bool
23.2905 +SemanticAnalysis::buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
23.2906 + FixedArray **argsp, FixedArray **defaultsp)
23.2907 +{
23.2908 + Local<FixedArray> args(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
23.2909 + if (!args)
23.2910 + return false;
23.2911 +
23.2912 + Local<FixedArray> defaults(zone_);
23.2913 +
23.2914 + // Apply types to arguments.
23.2915 + for (size_t i = 0; i < sig.parameters()->length(); i++) {
23.2916 + Parameter *parameter = sig.parameters()->at(i);
23.2917 +
23.2918 +#if 0
23.2919 + Local<Type> type(zone_, bindType(parameter->variable()->pos(), parameter->type()));
23.2920 + if (!type)
23.2921 + return false;
23.2922 +
23.2923 + if (parameter->reference()) {
23.2924 + if (parameter->dimensions()) {
23.2925 + cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
23.2926 + return false;
23.2927 + }
23.2928 +
23.2929 + if (type->isStruct()) {
23.2930 + cc_.reportError(parameter->variable()->pos(), Message_StructCantBeReference);
23.2931 + return false;
23.2932 + }
23.2933 +
23.2934 + type = zone_->types()->getReference(type, parameter->isConst());
23.2935 + if (!type)
23.2936 + return false;
23.2937 + } else if (parameter->dimensions()) {
23.2938 + type = buildArrayType(type, parameter->dimensions(), parameter->isConst());
23.2939 + if (!type)
23.2940 + return false;
23.2941 +
23.2942 + if (kind == TOK_NATIVE && type->levels() > 1) {
23.2943 + cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
23.2944 + return false;
23.2945 + }
23.2946 + }
23.2947 +
23.2948 + if (IsScalarString(type)) {
23.2949 + cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.2950 + return false;
23.2951 + }
23.2952 +
23.2953 + args->set(zone_, i, type);
23.2954 + parameter->variable()->setType(type);
23.2955 +
23.2956 + if (parameter->initializer()) {
23.2957 + if (!defaults) {
23.2958 + defaults = FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old);
23.2959 + if (!defaults)
23.2960 + return false;
23.2961 + }
23.2962 +
23.2963 + Local<Box> box(zone_, evaluateDefaultParameter(type, parameter));
23.2964 + if (!box)
23.2965 + return false;
23.2966 +
23.2967 + defaults->set(zone_, i, box);
23.2968 + }
23.2969 +#endif
23.2970 + }
23.2971 +
23.2972 + *argsp = args;
23.2973 + *defaultsp = defaults;
23.2974 +
23.2975 + return true;
23.2976 +}
23.2977 +
23.2978 +void
23.2979 +SemanticAnalysis::visit(FunctionTypeStatement *node)
23.2980 +{
23.2981 + if (node->decl()->type())
23.2982 + return;
23.2983 +
23.2984 + Local<FixedArray> args(zone_);
23.2985 + Local<FixedArray> defaults(zone_);
23.2986 +
23.2987 + const FunctionSignature &sig= node->signature();
23.2988 + if (!buildFunctionArgs(node,
23.2989 + TOK_STOCK,
23.2990 + sig,
23.2991 + args.address(),
23.2992 + defaults.address()))
23.2993 + {
23.2994 + return;
23.2995 + }
23.2996 +
23.2997 +#if 0
23.2998 + Local<Type> returnType(zone_);
23.2999 + if (sig.returnType())
23.3000 + returnType = bindType(node->pos(), sig.returnType());
23.3001 + else
23.3002 + returnType = zone_->types()->getPrimitive(PrimitiveType_Int32);
23.3003 +
23.3004 + if (!returnType)
23.3005 + return;
23.3006 +
23.3007 + Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args, defaults));
23.3008 + if (!funtype)
23.3009 + return;
23.3010 +
23.3011 + node->decl()->setType(funtype);
23.3012 +#endif
23.3013 +}
23.3014 +
23.3015 +Type *
23.3016 +SemanticAnalysis::buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst)
23.3017 +{
23.3018 + Local<Type> arrayType(zone_, type);
23.3019 +
23.3020 + unsigned dimcount = dimensions->length();
23.3021 + if (type->isArray())
23.3022 + dimcount += type->levels();
23.3023 +
23.3024 + if (dimcount > MAX_ARRAY_DEPTH) {
23.3025 + cc_.reportError(dimensions->at(dimensions->length() - 1)->pos(),
23.3026 + Message_MaximumArrayDepth);
23.3027 + return false;
23.3028 + }
23.3029 +
23.3030 + // Note: constness is sort of bogus. Fix this sometime.
23.3031 + for (size_t i = dimensions->length() - 1; i < dimensions->length(); i--) {
23.3032 + Expression *expr = dimensions->at(i);
23.3033 + if (!expr) {
23.3034 + arrayType = zone_->types()->newArray(arrayType, Type::DYNAMIC_ARRAY_SIZE, isConst);
23.3035 + if (!arrayType)
23.3036 + return NULL;
23.3037 +
23.3038 + continue;
23.3039 + }
23.3040 +
23.3041 + BoxedPrimitive box;
23.3042 + if (!EvaluateForConstant(expr, &box) || box.type() != PrimitiveType_Int32) {
23.3043 + cc_.reportError(expr->pos(), Message_ArraySizeMustBeConstant);
23.3044 + return NULL;
23.3045 + }
23.3046 +
23.3047 + if (box.toInt() <= 0) {
23.3048 + cc_.reportError(expr->pos(), Message_BadArraySize);
23.3049 + return NULL;
23.3050 + }
23.3051 +
23.3052 + arrayType = zone_->types()->newArray(arrayType, box.toInt(), isConst);
23.3053 + if (!arrayType)
23.3054 + return NULL;
23.3055 + }
23.3056 +
23.3057 + return arrayType;
23.3058 +}
23.3059 +
23.3060 +bool
23.3061 +SemanticAnalysis::preanalyze(FunctionStatement *node)
23.3062 +{
23.3063 + Local<FixedArray> args(zone_);
23.3064 + Local<FixedArray> defaults(zone_);
23.3065 +
23.3066 + const FunctionSignature &sig = node->signature();
23.3067 + if (!buildFunctionArgs(node,
23.3068 + node->fun()->token(),
23.3069 + sig,
23.3070 + args.address(),
23.3071 + defaults.address()))
23.3072 + {
23.3073 + return false;
23.3074 + }
23.3075 +
23.3076 +#if 0
23.3077 + Local<Type> returnType(zone_);
23.3078 + if (sig.returnType() ||
23.3079 + node->hasExplicitReturn() ||
23.3080 + node->fun()->isNative())
23.3081 + {
23.3082 + returnType = bindType(node->pos(), sig.returnType());
23.3083 + } else {
23.3084 + returnType = zone_->types()->getVoid();
23.3085 + }
23.3086 + if (!returnType)
23.3087 + return false;
23.3088 +
23.3089 + if (sig.returnDimensions()) {
23.3090 + returnType = buildArrayType(returnType, sig.returnDimensions(), false);
23.3091 + if (!returnType)
23.3092 + return false;
23.3093 + }
23.3094 +
23.3095 + if (IsScalarString(returnType)) {
23.3096 + cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.3097 + return false;
23.3098 + }
23.3099 +
23.3100 + Local<Type> funtype(zone_);
23.3101 + if (node->fun()->isNative())
23.3102 + funtype = zone_->types()->newNative(returnType, args, defaults, node->fun()->isNativeVariadic());
23.3103 + else
23.3104 + funtype = zone_->types()->newFunction(returnType, args, defaults);
23.3105 + if (!funtype)
23.3106 + return false;
23.3107 +
23.3108 + // If the function already has a type, it was forward declared before, and
23.3109 + // now this is our chance to type check the second declaration.
23.3110 + if (node->fun()->type()) {
23.3111 + Local<Type> forward(zone_, node->fun()->type());
23.3112 + if (!Type::Compare(funtype, forward)) {
23.3113 + cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
23.3114 + return false;
23.3115 + }
23.3116 + node->fun()->setForwardType(forward);
23.3117 + }
23.3118 +
23.3119 + node->fun()->setType(funtype);
23.3120 +#endif
23.3121 +
23.3122 + return true;
23.3123 +}
23.3124 +
23.3125 +void
23.3126 +SemanticAnalysis::visit(FunctionStatement *node)
23.3127 +{
23.3128 + function_ = node->fun();
23.3129 + scope_ = node->scope();
23.3130 +
23.3131 + ControlScope control(&control_);
23.3132 + if (node->body()) {
23.3133 + node->body()->accept(this);
23.3134 +
23.3135 + ControlStatus status = control.status();
23.3136 + if (status.returns() == Returns_Sometimes) {
23.3137 + cc_.reportError(node->pos(), Message_NotAllPathsReturnValue);
23.3138 + } else if (status.returns() == Returns_Never) {
23.3139 + if (!function_->type()->returnType()->isVoid())
23.3140 + cc_.reportError(node->pos(), Message_MissingReturnValue);
23.3141 + }
23.3142 + }
23.3143 +
23.3144 + scope_ = NULL;
23.3145 + function_ = NULL;
23.3146 +}
23.3147 +
23.3148 +void
23.3149 +SemanticAnalysis::typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given)
23.3150 +{
23.3151 + cc_.reportError(pos, Message_TypeMismatch,
23.3152 + GetTypeName(actual),
23.3153 + GetTypeName(given));
23.3154 +}
23.3155 +
23.3156 +bool
23.3157 +SemanticAnalysis::typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> argGiven,
23.3158 + Handle<Type> argActual, bool forAssign)
23.3159 +{
23.3160 + Local<Type> actual(zone_, argActual);
23.3161 + Local<Type> given(zone_, argGiven);
23.3162 +
23.3163 + if (!given->isArray()) {
23.3164 + cc_.reportError(pos, Message_ExpectedArray);
23.3165 + return false;
23.3166 + }
23.3167 + if (given->levels() != actual->levels()) {
23.3168 + cc_.reportError(pos, Message_ArrayDimensionsMismatch);
23.3169 + return false;
23.3170 + }
23.3171 +
23.3172 + unsigned level = 1;
23.3173 + while (given->isArray()) {
23.3174 + if (actual->isFixedLength()) {
23.3175 + if (forAssign) {
23.3176 + if (!given->isFixedLength()) {
23.3177 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
23.3178 + return false;
23.3179 + }
23.3180 +
23.3181 + if (actual->isCharArray()) {
23.3182 + // String assignment can have a truncated |given|.
23.3183 + if (given->fixedLength() > actual->fixedLength()) {
23.3184 + cc_.reportError(pos, Message_ArrayAssignmentTooBig);
23.3185 + return false;
23.3186 + }
23.3187 + } else {
23.3188 + if (given->fixedLength() != actual->fixedLength()) {
23.3189 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
23.3190 + return false;
23.3191 + }
23.3192 + }
23.3193 + }
23.3194 + } else if (given->isFixedLength()) {
23.3195 + // We do not allow assignments in the form:
23.3196 + // [][] = [][Y]
23.3197 + //
23.3198 + // Otherwise, the following code could break the size guarantees
23.3199 + // of the right-hand side:
23.3200 + //
23.3201 + // new x[][5];
23.3202 + // new y[][];
23.3203 + // new z[3];
23.3204 + //
23.3205 + // y = x;
23.3206 + // y[0] = z;
23.3207 + //
23.3208 + // Now |x[0]| contains a 4-length array.
23.3209 + if (level > 1) {
23.3210 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
23.3211 + return false;
23.3212 + }
23.3213 + }
23.3214 + given = given->contained();
23.3215 + actual = actual->contained();
23.3216 + level++;
23.3217 + }
23.3218 +
23.3219 + return typeCheckAssignment(pos, given, actual, forAssign);
23.3220 +}
23.3221 +
23.3222 +bool
23.3223 +SemanticAnalysis::typeCheckAssignment(const SourcePosition &pos, Handle<Type> argGiven,
23.3224 + Handle<Type> argActual, bool forAssign)
23.3225 +{
23.3226 + Local<Type> actual(zone_, argActual);
23.3227 + Local<Type> given(zone_, argGiven);
23.3228 +
23.3229 + if (actual->isArray())
23.3230 + return typeCheckArrayAssignment(pos, given, actual, forAssign);
23.3231 +
23.3232 + if (given->isArray()) {
23.3233 + cc_.reportError(pos, Message_CannotAssignArrayToScalar);
23.3234 + return false;
23.3235 + }
23.3236 +
23.3237 + // The given type may not have been dereferenced.
23.3238 + if (given->isReference())
23.3239 + given = given->contained();
23.3240 + if (actual->isReference())
23.3241 + actual = actual->contained();
23.3242 +
23.3243 + // We coerce unchecked to a few things.
23.3244 + if (actual->isUnchecked() || given->isUnchecked()) {
23.3245 + Type *check = actual->isUnchecked() ? given : actual;
23.3246 + if (check->isUnchecked() ||
23.3247 + check->isEnum() ||
23.3248 + check->isInt32() ||
23.3249 + check->isBool() ||
23.3250 + check->isFloat())
23.3251 + {
23.3252 + return true;
23.3253 + }
23.3254 + typeMismatch(pos, actual, given);
23.3255 + return false;
23.3256 + }
23.3257 +
23.3258 + if (given->isFunction() && actual->isFunction()) {
23.3259 + if (!Type::Compare(given, actual)) {
23.3260 + typeMismatch(pos, actual, given);
23.3261 + return false;
23.3262 + }
23.3263 + return true;
23.3264 + }
23.3265 +
23.3266 + if (actual->isEnum()) {
23.3267 + if (!given->isEnum() || actual != given) {
23.3268 + typeMismatch(pos, actual, given);
23.3269 + return false;
23.3270 + }
23.3271 + return true;
23.3272 + }
23.3273 +
23.3274 + if (actual->isStruct()) {
23.3275 + if (!given->isStruct() || actual != given) {
23.3276 + typeMismatch(pos, actual, given);
23.3277 + return false;
23.3278 + }
23.3279 + return true;
23.3280 + }
23.3281 +
23.3282 + if (given->isEnum() || given->isFunction() || given->isStruct()) {
23.3283 + typeMismatch(pos, actual, given);
23.3284 + return false;
23.3285 + }
23.3286 +
23.3287 + // This coercion is trivial.
23.3288 + if (given->isBool() && actual->isInt32())
23.3289 + return true;
23.3290 +
23.3291 + if (given->primitive() != actual->primitive()) {
23.3292 + typeMismatch(pos, actual, given);
23.3293 + return false;
23.3294 + }
23.3295 +
23.3296 + return true;
23.3297 +}
23.3298 +
23.3299 +bool
23.3300 +SemanticAnalysis::typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual)
23.3301 +{
23.3302 + return typeCheckAssignment(node->pos(), given, actual, false);
23.3303 +}
23.3304 +
23.3305 +bool
23.3306 +SemanticAnalysis::checkArgumentCount(Handle<Type> type, unsigned actual)
23.3307 +{
23.3308 + if (type->parameters()->length() == actual)
23.3309 + return true;
23.3310 +
23.3311 + if (actual > type->parameters()->length()) {
23.3312 + if (!type->isNative() || !type->isNativeVariadic())
23.3313 + return false;
23.3314 + return true;
23.3315 + }
23.3316 +
23.3317 + if (!type->defaults())
23.3318 + return false;
23.3319 +
23.3320 + // Missing arguments. See if there's a default argument for each missing
23.3321 + // actual.
23.3322 + for (unsigned i = actual; i < type->parameters()->length(); i++) {
23.3323 + if (!type->defaults()->at(i))
23.3324 + return false;
23.3325 + }
23.3326 +
23.3327 + return true;
23.3328 +}
23.3329 +
23.3330 +void
23.3331 +SemanticAnalysis::visit(CallExpression *node)
23.3332 +{
23.3333 + Local<Type> type(zone_, visitForLoad(node->callee()));
23.3334 + if (!type)
23.3335 + return;
23.3336 +
23.3337 + if (!type->isFunction()) {
23.3338 + cc_.reportError(node->pos(), Message_CalleeNotFunction);
23.3339 + return;
23.3340 + }
23.3341 +
23.3342 + if (!checkArgumentCount(type, node->arguments()->length())) {
23.3343 + cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
23.3344 + return;
23.3345 + }
23.3346 +
23.3347 + // NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
23.3348 + // if (fun->isForward()) {
23.3349 + // cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
23.3350 + // return;
23.3351 + // }
23.3352 +
23.3353 + for (unsigned i = 0; i < node->arguments()->length(); i++) {
23.3354 + // Note: we don't compute references unless the callee needs a
23.3355 + // reference type.
23.3356 + Expression *expression = node->arguments()->at(i);
23.3357 + Local<Type> given(zone_, visitAndApplyType(expression));
23.3358 + if (!given)
23.3359 + return;
23.3360 +
23.3361 + // Since we skip a load, check for a call expression that returns void.
23.3362 + if (given->isVoid()) {
23.3363 + assert(expression->isCallExpression());
23.3364 + CallExpression *call = expression->toCallExpression();
23.3365 + cc_.reportError(call->callee()->pos(), Message_FunctionDoesNotReturnValue);
23.3366 + return;
23.3367 + }
23.3368 +
23.3369 + bool mustComputeReference;
23.3370 + if (i >= type->parameters()->length()) {
23.3371 + // Special handling for natives. Arguments past the formal must
23.3372 + // always have references computed. However, arrays are already
23.3373 + // references for natives.
23.3374 + assert(type->isNative() && type->isNativeVariadic());
23.3375 + mustComputeReference = !given->isReference() && !given->isArray();
23.3376 + } else {
23.3377 + Local<Type> actual(zone_, type->parameterAt(i));
23.3378 +
23.3379 + if (expression->isIndexExpression()) {
23.3380 + // Disabled until we can make it work.
23.3381 +#if 0
23.3382 + if (actual->isArray()) {
23.3383 + // We special case the ability to pass x[y] into x[], which
23.3384 + // creates an array slice. We only do this if we know the
23.3385 + // assignment would otherwise not type-check.
23.3386 + IndexExpression *index = expression->toIndexExpression();
23.3387 + if (index->left()->type()->levels() == actual->levels())
23.3388 + given = index->left()->type();
23.3389 + } else
23.3390 +#endif
23.3391 + if (actual->isReference()) {
23.3392 + cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
23.3393 + return;
23.3394 + }
23.3395 + }
23.3396 +
23.3397 + if (!typeCheckParameter(expression, given, actual))
23.3398 + return;
23.3399 + mustComputeReference = actual->isReference() && !given->isReference();
23.3400 + }
23.3401 +
23.3402 + // If the actual is a reference, and the given is not, we'll need to
23.3403 + // compute a reference, which may be allocated on the stack.
23.3404 + if (mustComputeReference)
23.3405 + scope_->setUsesLifoHeap();
23.3406 + }
23.3407 +
23.3408 + node->setType(type->returnType());
23.3409 +}
23.3410 +
23.3411 +void
23.3412 +SemanticAnalysis::ControlScope::inherit(const ControlStatus &other)
23.3413 +{
23.3414 + if (other.returns() < status().returns())
23.3415 + return;
23.3416 +
23.3417 + if (other.terminates())
23.3418 + terminate(other.returns());
23.3419 + else
23.3420 + returns(other.returns());
23.3421 +}
23.3422 +
23.3423 +void
23.3424 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
23.3425 +{
23.3426 + // If both sides terminate in a return, we consider this a return as well.
23.3427 + if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
23.3428 + terminate(Returns_Always);
23.3429 + return;
23.3430 + }
23.3431 +
23.3432 + ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
23.3433 + ? Returns_Never
23.3434 + : Returns_Sometimes;
23.3435 +
23.3436 + if (left.terminates() && right.terminates())
23.3437 + terminate(status);
23.3438 + else
23.3439 + returns(status);
23.3440 +}
23.3441 +
23.3442 +void
23.3443 +SemanticAnalysis::visit(IfStatement *node)
23.3444 +{
23.3445 + Local<Type> type(zone_, visitForLoad(node->condition()));
23.3446 + if (!type)
23.3447 + return;
23.3448 +
23.3449 + if (!canTest(node, type))
23.3450 + return;
23.3451 +
23.3452 + ControlStatus trueBranch = visitForControl(node->ifTrue());
23.3453 + ControlStatus falseBranch = ControlStatus(false, Returns_Never);
23.3454 +
23.3455 + if (node->ifFalse())
23.3456 + falseBranch = visitForControl(node->ifFalse());
23.3457 +
23.3458 + control_->merge(trueBranch, falseBranch);
23.3459 +}
23.3460 +
23.3461 +void
23.3462 +SemanticAnalysis::visit(IndexExpression *node)
23.3463 +{
23.3464 + Local<Type> left(zone_, visitForLoad(node->left()));
23.3465 + Local<Type> right(zone_, visitForLoad(node->right()));
23.3466 +
23.3467 + if (!left || !right)
23.3468 + return;
23.3469 +
23.3470 + if (!right->isInt32() && !right->isEnum()) {
23.3471 + cc_.reportError(node->right()->pos(), Message_IndexMustBeInteger);
23.3472 + return;
23.3473 + }
23.3474 + if (!left->isArray()) {
23.3475 + cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
23.3476 + return;
23.3477 + }
23.3478 +
23.3479 + // Note: char arrays are automatically up-casted to return an int32.
23.3480 + if (left->isCharArray())
23.3481 + node->setType(zone_->types()->getPrimitive(PrimitiveType_Int32));
23.3482 + else
23.3483 + node->setType(left->contained());
23.3484 +}
23.3485 +
23.3486 +void
23.3487 +SemanticAnalysis::visit(FieldExpression *node)
23.3488 +{
23.3489 + Local<Type> left(zone_, visitForLoad(node->left()));
23.3490 + if (!left)
23.3491 + return;
23.3492 +
23.3493 + if (!left->isStruct()) {
23.3494 + cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
23.3495 + GetTypeName(left));
23.3496 + return;
23.3497 + }
23.3498 +
23.3499 + Local<String> field(zone_, node->field());
23.3500 +
23.3501 + unsigned offset;
23.3502 + Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
23.3503 + if (!desc) {
23.3504 + cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
23.3505 + GetTypeName(left));
23.3506 + return;
23.3507 + }
23.3508 +
23.3509 + node->setFieldIndex(offset);
23.3510 + node->setType(desc->type());
23.3511 +}
23.3512 +
23.3513 +void
23.3514 +SemanticAnalysis::visit(EnumStatement *node)
23.3515 +{
23.3516 + Local<String> name(zone_, node->name());
23.3517 + Local<Type> type(zone_);
23.3518 + if (name)
23.3519 + type = zone_->types()->newEnum(name);
23.3520 + else
23.3521 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
23.3522 +
23.3523 + if (!type)
23.3524 + return;
23.3525 +
23.3526 + if (node->decl())
23.3527 + node->decl()->setType(type);
23.3528 +
23.3529 + int value = 0;
23.3530 + for (size_t i = 0; i < node->entries()->length(); i++) {
23.3531 + EnumStatement::Entry &entry = node->entries()->at(i);
23.3532 +
23.3533 + BoxedPrimitive box = BoxedPrimitive::Int(value);
23.3534 + if (entry.expr) {
23.3535 + entry.expr->accept(this);
23.3536 + if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
23.3537 + cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
23.3538 + return;
23.3539 + }
23.3540 +
23.3541 + assert(box.type() == PrimitiveType_Int32);
23.3542 + value = box.toInt();
23.3543 + }
23.3544 +
23.3545 +#if 0
23.3546 + entry.name->set(type, box);
23.3547 +#endif
23.3548 + value++;
23.3549 + }
23.3550 +}
23.3551 +
23.3552 +static int
23.3553 +SortCaseIntValues(const void *p1, const void *p2)
23.3554 +{
23.3555 + CaseValue *v1 = (CaseValue *)p1;
23.3556 + CaseValue *v2 = (CaseValue *)p2;
23.3557 +
23.3558 + return v1->box.toInt() - v2->box.toInt();
23.3559 +}
23.3560 +
23.3561 +void
23.3562 +SemanticAnalysis::visit(SwitchStatement *node)
23.3563 +{
23.3564 + Local<Type> caseType(zone_, visitForLoad(node->expression()));
23.3565 + if (!caseType)
23.3566 + return;
23.3567 +
23.3568 + if (!caseType->isEnum() && !caseType->isInt32()) {
23.3569 + cc_.reportError(node->pos(), Message_CaseMustBeInteger);
23.3570 + return;
23.3571 + }
23.3572 +
23.3573 + PoolList<CaseValue> *values = new (zone_->pool()) PoolList<CaseValue>();
23.3574 + ControlStatus status = ControlStatus(false, Returns_Never);
23.3575 +
23.3576 + Local<Type> check(zone_);
23.3577 + for (size_t i = 0; i < node->cases()->length(); i++) {
23.3578 + Case *c = node->cases()->at(i);
23.3579 +
23.3580 + check = visitForLoad(c->expression());
23.3581 + if (!check)
23.3582 + return;
23.3583 +
23.3584 + if (!typeCheckAssignment(c->expression()->pos(), check, caseType, false))
23.3585 + return;
23.3586 +
23.3587 + CaseValue v(i);
23.3588 + if (!EvaluateForConstant(c->expression(), &v.box)) {
23.3589 + cc_.reportError(c->expression()->pos(), Message_CaseMustBeConstant);
23.3590 + return;
23.3591 + }
23.3592 + if (!values->append(v))
23.3593 + return;
23.3594 +
23.3595 + if (c->others()) {
23.3596 + for (size_t j = 0; j < c->others()->length(); j++) {
23.3597 + Expression *expr = c->others()->at(j);
23.3598 + check = visitForLoad(expr);
23.3599 + if (!check)
23.3600 + return;
23.3601 +
23.3602 + if (!typeCheckAssignment(expr->pos(), check, caseType, false))
23.3603 + return;
23.3604 +
23.3605 + CaseValue v(i);
23.3606 + if (!EvaluateForConstant(expr, &v.box)) {
23.3607 + cc_.reportError(expr->pos(), Message_CaseMustBeConstant);
23.3608 + return;
23.3609 + }
23.3610 + if (!values->append(v))
23.3611 + return;
23.3612 + }
23.3613 + }
23.3614 +
23.3615 + ControlStatus latest = visitForControl(c->statement());
23.3616 +
23.3617 + if (i != 0)
23.3618 + control_->merge(status, latest);
23.3619 +
23.3620 + status = latest;
23.3621 + }
23.3622 +
23.3623 + if (node->defaultCase()) {
23.3624 + ControlStatus latest = visitForControl(node->defaultCase());
23.3625 +
23.3626 + if (node->cases()->length()) {
23.3627 + // If we had any other cases, we must merge.
23.3628 + control_->merge(status, latest);
23.3629 + } else {
23.3630 + // Otherwise, control-flow always flows through here.
23.3631 + control_->inherit(latest);
23.3632 + }
23.3633 + } else if (node->cases()->length()) {
23.3634 + control_->merge(status, ControlStatus(false, Returns_Never));
23.3635 + }
23.3636 +
23.3637 + if (values->length() > 1) {
23.3638 + qsort(values->buffer(), values->length(), sizeof(CaseValue), SortCaseIntValues);
23.3639 +
23.3640 + for (size_t i = 1; i < values->length(); i++) {
23.3641 + CaseValue &prev = values->at(i - 1);
23.3642 + CaseValue &cur = values->at(i);
23.3643 + if (prev.box.toInt() == cur.box.toInt()) {
23.3644 + cc_.reportError(node->cases()->at(cur.statement)->expression()->pos(), Message_CaseHasSameValue);
23.3645 + return;
23.3646 + }
23.3647 + }
23.3648 + }
23.3649 +
23.3650 + node->setCaseValueList(values);
23.3651 +}
23.3652 +
23.3653 +void
23.3654 +SemanticAnalysis::visit(StructureStatement *node)
23.3655 +{
23.3656 +#if 0
23.3657 + // If this node already has a type, it was pre-analyzed, so skip it.
23.3658 + if (node->decl()->type())
23.3659 + return;
23.3660 +
23.3661 + FieldList *fields = node->fields();
23.3662 + Local<FixedArray> desctable(zone_, FixedArray::New(zone_, fields->length(), Heap::Tenure_Old));
23.3663 + if (!desctable)
23.3664 + return;
23.3665 +
23.3666 + Vector<unsigned> composedList;
23.3667 + StructureBufferBuilder builder;
23.3668 +
23.3669 + Local<Type> type(zone_);
23.3670 + Local<String> name(zone_);
23.3671 + Local<Descriptor> desc(zone_);
23.3672 + for (size_t i = 0; i < fields->length(); i++) {
23.3673 + StructureStatement::Field *field = fields->at(i);
23.3674 +
23.3675 + type = bindType(field->pos(), field->type());
23.3676 + if (!type)
23.3677 + return;
23.3678 +
23.3679 + if (field->dimensions()) {
23.3680 + type = buildArrayType(type, field->dimensions(), false);
23.3681 + if (!type)
23.3682 + return;
23.3683 +
23.3684 + if (!ArrayMap::Attach(zone_, type))
23.3685 + return;
23.3686 + }
23.3687 +
23.3688 + if (IsScalarString(type)) {
23.3689 + cc_.reportError(field->pos(), Message_CannotDeclareStringCell);
23.3690 + return;
23.3691 + }
23.3692 +
23.3693 + unsigned offset;
23.3694 + if (!builder.add(type, &offset))
23.3695 + return;
23.3696 +
23.3697 + name = field->name();
23.3698 + desc = Descriptor::New(zone_, name, type, offset);
23.3699 + if (!desc)
23.3700 + return;
23.3701 +
23.3702 + desctable->set(zone_, i, desc);
23.3703 +
23.3704 + if (type->isStruct() || type->isArray()) {
23.3705 + if (!composedList.append(i))
23.3706 + return;
23.3707 + }
23.3708 + }
23.3709 +
23.3710 + Local<FixedArray> composed(zone_);
23.3711 + if (composedList.length()) {
23.3712 + composed = FixedArray::New(zone_, composedList.length(), Heap::Tenure_Old);
23.3713 + if (!composed)
23.3714 + return;
23.3715 +
23.3716 + for (unsigned i = 0; i < composedList.length(); i++)
23.3717 + composed->set(zone_, i, desctable->at(i));
23.3718 + }
23.3719 +
23.3720 + Local<StructMap> map(zone_, StructMap::New(zone_, builder, composed));
23.3721 + if (!map)
23.3722 + return;
23.3723 +
23.3724 + name = node->decl()->name();
23.3725 + type = zone_->types()->newStruct(name, desctable, map);
23.3726 + if (!type)
23.3727 + return;
23.3728 +
23.3729 + map->setType(type);
23.3730 + node->decl()->setType(type);
23.3731 +#endif
23.3732 +}
23.3733 +
23.3734 +void
23.3735 +SemanticAnalysis::visit(StringLiteral *node)
23.3736 +{
23.3737 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Char));
23.3738 + if (!type)
23.3739 + return;
23.3740 +
23.3741 + type = Type::NewArray(zone_, type, node->string()->length() + 1, true);
23.3742 + if (!type)
23.3743 + return;
23.3744 +
23.3745 + node->setType(type);
23.3746 +}
23.3747 +
23.3748 +void
23.3749 +SemanticAnalysis::visit(FloatLiteral *node)
23.3750 +{
23.3751 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
23.3752 + if (!type)
23.3753 + return;
23.3754 +
23.3755 + node->setType(type);
23.3756 +}
23.3757 +
23.3758 +void
23.3759 +SemanticAnalysis::visit(BreakStatement *node)
23.3760 +{
23.3761 + if (!loop_) {
23.3762 + cc_.reportError(node->pos(), Message_BreakOutsideLoop);
23.3763 + return;
23.3764 + }
23.3765 +
23.3766 + // Note: ignore breaks that occur in unreachable control-flow.
23.3767 + if (!control_->status().terminates())
23.3768 + loop_->addBreak();
23.3769 +
23.3770 + control_->terminate(Returns_Never);
23.3771 +}
23.3772 +
23.3773 +void
23.3774 +SemanticAnalysis::visit(ContinueStatement *node)
23.3775 +{
23.3776 + if (!loop_) {
23.3777 + cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
23.3778 + return;
23.3779 + }
23.3780 +
23.3781 + // Note: ignore continues that occur in unreachable control-flow.
23.3782 + if (!control_->status().terminates())
23.3783 + loop_->addContinue();
23.3784 +
23.3785 + control_->terminate(Returns_Never);
23.3786 +}
23.3787 +
23.3788 +void
23.3789 +SemanticAnalysis::visit(ArrayLiteral *node)
23.3790 +{
23.3791 + // We should never visit this.
23.3792 + cc_.reportError(node->pos(), Message_UnexpectedArrayLiteral);
23.3793 +}
23.3794 +
23.3795 +void
23.3796 +SemanticAnalysis::visit(ImportStatement *node)
23.3797 +{
23.3798 +}
23.3799 +
23.3800 #endif
23.3801 \ No newline at end of file
24.1 --- a/src/OldSema.h Mon Jun 10 00:46:29 2013 +0100
24.2 +++ b/src/OldSema.h Mon Jun 10 01:04:43 2013 +0100
24.3 @@ -1,237 +1,237 @@
24.4 -/* vim: set ts=4 sw=4 tw=99 et:
24.5 - *
24.6 - * Copyright (C) 2012 David Anderson
24.7 - *
24.8 - * This file is part of JITCraft.
24.9 - *
24.10 - * JITCraft is free software: you can redistribute it and/or modify it under
24.11 - * the terms of the GNU General Public License as published by the Free
24.12 - * Software Foundation, either version 3 of the License, or (at your option)
24.13 - * any later version.
24.14 - *
24.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
24.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24.18 - *
24.19 - * You should have received a copy of the GNU General Public License along with
24.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
24.21 - */
24.22 -#ifndef _include_semantic_analysis_h_
24.23 -#define _include_semantic_analysis_h_
24.24 -
24.25 -#include <assert.h>
24.26 -#include "AST.h"
24.27 -#include "../Types.h"
24.28 -
24.29 -namespace ke {
24.30 -
24.31 -class Box;
24.32 -
24.33 -class SemanticAnalysis : public AstVisitor
24.34 -{
24.35 - Zone *zone_;
24.36 - CompileContext &cc_;
24.37 - ParseTree *tree_;
24.38 - Scope *scope_;
24.39 - NamedFunction *function_;
24.40 -
24.41 - enum ReturnStatus
24.42 - {
24.43 - Returns_Never,
24.44 - Returns_Sometimes,
24.45 - Returns_Always
24.46 - };
24.47 -
24.48 - // Tuple that describes whether a path terminates control flow, and
24.49 - // if it is guaranteed to end in a return.
24.50 - class ControlStatus
24.51 - {
24.52 - bool terminates_;
24.53 - ReturnStatus returns_;
24.54 -
24.55 - public:
24.56 - ControlStatus(bool terminates, ReturnStatus returns)
24.57 - : terminates_(terminates),
24.58 - returns_(returns)
24.59 - {
24.60 - }
24.61 -
24.62 - bool terminates() const {
24.63 - return terminates_;
24.64 - }
24.65 - ReturnStatus returns() const {
24.66 - return returns_;
24.67 - }
24.68 - };
24.69 -
24.70 - // Used to keep track of terminating control flow and return statements
24.71 - // inside control structures.
24.72 - class ControlScope
24.73 - {
24.74 - ReturnStatus returns_;
24.75 - ControlScope **prevp_;
24.76 - ControlScope *prev_;
24.77 - bool terminates_;
24.78 -
24.79 - public:
24.80 - ControlScope(ControlScope **prev)
24.81 - : returns_(Returns_Never),
24.82 - prevp_(prev),
24.83 - prev_(*prev),
24.84 - terminates_(false)
24.85 - {
24.86 - *prevp_ = this;
24.87 - }
24.88 -
24.89 - ControlStatus status() const {
24.90 - return ControlStatus(terminates_, returns_);
24.91 - }
24.92 -
24.93 - // We allow multiple terminators, but only the first one takes effect.
24.94 - // For example, |break; continue;| is legal but the continue is
24.95 - // unreachable.
24.96 - void returns(ReturnStatus status) {
24.97 - if (terminates_)
24.98 - return;
24.99 - if (status > returns_)
24.100 - returns_ = status;
24.101 - }
24.102 - void terminate(ReturnStatus status) {
24.103 - if (terminates_)
24.104 - return;
24.105 - terminates_ = true;
24.106 - returns_ = status;
24.107 - }
24.108 - void merge(const ControlStatus &left, const ControlStatus &right);
24.109 - void inherit(const ControlStatus &other);
24.110 -
24.111 - ~ControlScope()
24.112 - {
24.113 - *prevp_ = prev_;
24.114 - }
24.115 - };
24.116 -
24.117 - class LoopScope
24.118 - {
24.119 - LoopScope **prevp_;
24.120 - LoopScope *prev_;
24.121 - unsigned breaks_;
24.122 - unsigned continues_;
24.123 -
24.124 - public:
24.125 - LoopScope(LoopScope **prev)
24.126 - : prevp_(prev),
24.127 - prev_(*prev),
24.128 - breaks_(0),
24.129 - continues_(0)
24.130 - {
24.131 - *prevp_ = this;
24.132 - }
24.133 -
24.134 - ~LoopScope()
24.135 - {
24.136 - *prevp_ = prev_;
24.137 - }
24.138 -
24.139 - void addBreak() {
24.140 - breaks_++;
24.141 - }
24.142 - void addContinue() {
24.143 - continues_++;
24.144 - }
24.145 - unsigned breaks() const {
24.146 - return breaks_;
24.147 - }
24.148 - unsigned continues() const {
24.149 - return continues_;
24.150 - }
24.151 - };
24.152 -
24.153 - ControlScope *control_;
24.154 - LoopScope *loop_;
24.155 -
24.156 - private:
24.157 - bool canTest(AstNode *node, Handle<Type> type);
24.158 - void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
24.159 - void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
24.160 - void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
24.161 - Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
24.162 -
24.163 - Type *bindType(const SourcePosition &pos, BoundName *name);
24.164 -
24.165 - // These check if one type is compatible with another type, for various
24.166 - // purposes, like:
24.167 - // return (expr) matches function return type
24.168 - // call(a, b) matches expected arg type
24.169 - // a = b matches declared type
24.170 - //
24.171 - bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
24.172 - bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
24.173 - bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
24.174 -
24.175 - Type *visitForLoad(Expression *expression);
24.176 - bool preanalyze(FunctionStatement *node);
24.177 - Type *visitForLValue(Expression *expression);
24.178 - Type *visitAndApplyType(Expression *expression);
24.179 - ControlStatus visitForControl(Statement *statement);
24.180 -
24.181 - bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
24.182 - bool inferFixedArrayLiteral(ArrayLiteral *literal,
24.183 - Handle<Type> type,
24.184 - int dims[MAX_ARRAY_DEPTH],
24.185 - unsigned dimcount,
24.186 - unsigned level);
24.187 -
24.188 - // Builds an array type used for parameters, returns, or field entries.
24.189 - Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
24.190 -
24.191 - Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
24.192 - bool checkArgumentCount(Handle<Type> type, unsigned actual);
24.193 - bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
24.194 - FixedArray **args, FixedArray **defaults);
24.195 -
24.196 - void markCallResultUsed(CallExpression *call);
24.197 -
24.198 - bool determineLiveFunctions();
24.199 -
24.200 - public:
24.201 - SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
24.202 - bool analyze();
24.203 -
24.204 - public:
24.205 - void visit(NameProxy *name);
24.206 - void visit(Assignment *node);
24.207 - void visit(BinaryExpression *node);
24.208 - void visit(ReturnStatement *node);
24.209 - void visit(ForStatement *node);
24.210 - void visit(BlockStatement *node);
24.211 - void visit(VariableDeclaration *node);
24.212 - void visit(IntegerLiteral *node);
24.213 - void visit(ExpressionStatement *node);
24.214 - void visit(FunctionStatement *node);
24.215 - void visit(CallExpression *node);
24.216 - void visit(IfStatement *node);
24.217 - void visit(IndexExpression *node);
24.218 - void visit(EnumStatement *node);
24.219 - void visit(FloatLiteral *node);
24.220 - void visit(WhileStatement *node);
24.221 - void visit(BreakStatement *node);
24.222 - void visit(ContinueStatement *node);
24.223 - void visit(StringLiteral *node);
24.224 - void visit(IncDecExpression *node);
24.225 - void visit(UnaryExpression *node);
24.226 - void visit(TernaryExpression *node);
24.227 - void visit(BooleanLiteral *node);
24.228 - void visit(StructureStatement *node);
24.229 - void visit(FieldExpression *node);
24.230 - void visit(SwitchStatement *node);
24.231 - void visit(FunctionTypeStatement *node);
24.232 - void visit(ArrayLiteral *node);
24.233 - void visit(ImportStatement *node);
24.234 -};
24.235 -
24.236 -const char *GetTypeName(Type *type);
24.237 -
24.238 -} // namespace ke
24.239 -
24.240 -#endif // _include_semantic_analysis_h_
24.241 +/* vim: set ts=4 sw=4 tw=99 et:
24.242 + *
24.243 + * Copyright (C) 2012 David Anderson
24.244 + *
24.245 + * This file is part of JITCraft.
24.246 + *
24.247 + * JITCraft is free software: you can redistribute it and/or modify it under
24.248 + * the terms of the GNU General Public License as published by the Free
24.249 + * Software Foundation, either version 3 of the License, or (at your option)
24.250 + * any later version.
24.251 + *
24.252 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
24.253 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24.254 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24.255 + *
24.256 + * You should have received a copy of the GNU General Public License along with
24.257 + * JITCraft. If not, see http://www.gnu.org/licenses/.
24.258 + */
24.259 +#ifndef _include_semantic_analysis_h_
24.260 +#define _include_semantic_analysis_h_
24.261 +
24.262 +#include <assert.h>
24.263 +#include "AST.h"
24.264 +#include "../Types.h"
24.265 +
24.266 +namespace ke {
24.267 +
24.268 +class Box;
24.269 +
24.270 +class SemanticAnalysis : public AstVisitor
24.271 +{
24.272 + Zone *zone_;
24.273 + CompileContext &cc_;
24.274 + ParseTree *tree_;
24.275 + Scope *scope_;
24.276 + NamedFunction *function_;
24.277 +
24.278 + enum ReturnStatus
24.279 + {
24.280 + Returns_Never,
24.281 + Returns_Sometimes,
24.282 + Returns_Always
24.283 + };
24.284 +
24.285 + // Tuple that describes whether a path terminates control flow, and
24.286 + // if it is guaranteed to end in a return.
24.287 + class ControlStatus
24.288 + {
24.289 + bool terminates_;
24.290 + ReturnStatus returns_;
24.291 +
24.292 + public:
24.293 + ControlStatus(bool terminates, ReturnStatus returns)
24.294 + : terminates_(terminates),
24.295 + returns_(returns)
24.296 + {
24.297 + }
24.298 +
24.299 + bool terminates() const {
24.300 + return terminates_;
24.301 + }
24.302 + ReturnStatus returns() const {
24.303 + return returns_;
24.304 + }
24.305 + };
24.306 +
24.307 + // Used to keep track of terminating control flow and return statements
24.308 + // inside control structures.
24.309 + class ControlScope
24.310 + {
24.311 + ReturnStatus returns_;
24.312 + ControlScope **prevp_;
24.313 + ControlScope *prev_;
24.314 + bool terminates_;
24.315 +
24.316 + public:
24.317 + ControlScope(ControlScope **prev)
24.318 + : returns_(Returns_Never),
24.319 + prevp_(prev),
24.320 + prev_(*prev),
24.321 + terminates_(false)
24.322 + {
24.323 + *prevp_ = this;
24.324 + }
24.325 +
24.326 + ControlStatus status() const {
24.327 + return ControlStatus(terminates_, returns_);
24.328 + }
24.329 +
24.330 + // We allow multiple terminators, but only the first one takes effect.
24.331 + // For example, |break; continue;| is legal but the continue is
24.332 + // unreachable.
24.333 + void returns(ReturnStatus status) {
24.334 + if (terminates_)
24.335 + return;
24.336 + if (status > returns_)
24.337 + returns_ = status;
24.338 + }
24.339 + void terminate(ReturnStatus status) {
24.340 + if (terminates_)
24.341 + return;
24.342 + terminates_ = true;
24.343 + returns_ = status;
24.344 + }
24.345 + void merge(const ControlStatus &left, const ControlStatus &right);
24.346 + void inherit(const ControlStatus &other);
24.347 +
24.348 + ~ControlScope()
24.349 + {
24.350 + *prevp_ = prev_;
24.351 + }
24.352 + };
24.353 +
24.354 + class LoopScope
24.355 + {
24.356 + LoopScope **prevp_;
24.357 + LoopScope *prev_;
24.358 + unsigned breaks_;
24.359 + unsigned continues_;
24.360 +
24.361 + public:
24.362 + LoopScope(LoopScope **prev)
24.363 + : prevp_(prev),
24.364 + prev_(*prev),
24.365 + breaks_(0),
24.366 + continues_(0)
24.367 + {
24.368 + *prevp_ = this;
24.369 + }
24.370 +
24.371 + ~LoopScope()
24.372 + {
24.373 + *prevp_ = prev_;
24.374 + }
24.375 +
24.376 + void addBreak() {
24.377 + breaks_++;
24.378 + }
24.379 + void addContinue() {
24.380 + continues_++;
24.381 + }
24.382 + unsigned breaks() const {
24.383 + return breaks_;
24.384 + }
24.385 + unsigned continues() const {
24.386 + return continues_;
24.387 + }
24.388 + };
24.389 +
24.390 + ControlScope *control_;
24.391 + LoopScope *loop_;
24.392 +
24.393 + private:
24.394 + bool canTest(AstNode *node, Handle<Type> type);
24.395 + void typeMismatch(const SourcePosition &pos, Handle<Type> actual, Handle<Type> given);
24.396 + void unaryTypeError(AstNode *node, TokenKind token, Handle<Type> type);
24.397 + void binaryTypeError(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
24.398 + Type *typeCheckBinary(AstNode *node, TokenKind token, Handle<Type> left, Handle<Type> right);
24.399 +
24.400 + Type *bindType(const SourcePosition &pos, BoundName *name);
24.401 +
24.402 + // These check if one type is compatible with another type, for various
24.403 + // purposes, like:
24.404 + // return (expr) matches function return type
24.405 + // call(a, b) matches expected arg type
24.406 + // a = b matches declared type
24.407 + //
24.408 + bool typeCheckArrayAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
24.409 + bool typeCheckAssignment(const SourcePosition &pos, Handle<Type> given, Handle<Type> actual, bool forAssign);
24.410 + bool typeCheckParameter(AstNode *node, Handle<Type> given, Handle<Type> actual);
24.411 +
24.412 + Type *visitForLoad(Expression *expression);
24.413 + bool preanalyze(FunctionStatement *node);
24.414 + Type *visitForLValue(Expression *expression);
24.415 + Type *visitAndApplyType(Expression *expression);
24.416 + ControlStatus visitForControl(Statement *statement);
24.417 +
24.418 + bool evaluateDimensions(ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]);
24.419 + bool inferFixedArrayLiteral(ArrayLiteral *literal,
24.420 + Handle<Type> type,
24.421 + int dims[MAX_ARRAY_DEPTH],
24.422 + unsigned dimcount,
24.423 + unsigned level);
24.424 +
24.425 + // Builds an array type used for parameters, returns, or field entries.
24.426 + Type *buildArrayType(Handle<Type> type, ExpressionList *dimensions, bool isConst);
24.427 +
24.428 + Box *evaluateDefaultParameter(Handle<Type> type, Parameter *parameter);
24.429 + bool checkArgumentCount(Handle<Type> type, unsigned actual);
24.430 + bool buildFunctionArgs(AstNode *node, TokenKind kind, const FunctionSignature &sig,
24.431 + FixedArray **args, FixedArray **defaults);
24.432 +
24.433 + void markCallResultUsed(CallExpression *call);
24.434 +
24.435 + bool determineLiveFunctions();
24.436 +
24.437 + public:
24.438 + SemanticAnalysis(Zone *zone, CompileContext &cc, ParseTree *tree);
24.439 + bool analyze();
24.440 +
24.441 + public:
24.442 + void visit(NameProxy *name);
24.443 + void visit(Assignment *node);
24.444 + void visit(BinaryExpression *node);
24.445 + void visit(ReturnStatement *node);
24.446 + void visit(ForStatement *node);
24.447 + void visit(BlockStatement *node);
24.448 + void visit(VariableDeclaration *node);
24.449 + void visit(IntegerLiteral *node);
24.450 + void visit(ExpressionStatement *node);
24.451 + void visit(FunctionStatement *node);
24.452 + void visit(CallExpression *node);
24.453 + void visit(IfStatement *node);
24.454 + void visit(IndexExpression *node);
24.455 + void visit(EnumStatement *node);
24.456 + void visit(FloatLiteral *node);
24.457 + void visit(WhileStatement *node);
24.458 + void visit(BreakStatement *node);
24.459 + void visit(ContinueStatement *node);
24.460 + void visit(StringLiteral *node);
24.461 + void visit(IncDecExpression *node);
24.462 + void visit(UnaryExpression *node);
24.463 + void visit(TernaryExpression *node);
24.464 + void visit(BooleanLiteral *node);
24.465 + void visit(StructureStatement *node);
24.466 + void visit(FieldExpression *node);
24.467 + void visit(SwitchStatement *node);
24.468 + void visit(FunctionTypeStatement *node);
24.469 + void visit(ArrayLiteral *node);
24.470 + void visit(ImportStatement *node);
24.471 +};
24.472 +
24.473 +const char *GetTypeName(Type *type);
24.474 +
24.475 +} // namespace ke
24.476 +
24.477 +#endif // _include_semantic_analysis_h_
25.1 --- a/src/Opcodes.cpp Mon Jun 10 00:46:29 2013 +0100
25.2 +++ b/src/Opcodes.cpp Mon Jun 10 01:04:43 2013 +0100
25.3 @@ -1,350 +1,350 @@
25.4 -/* vim: set ts=4 sw=4 tw=99 et:
25.5 - *
25.6 - * Copyright (C) 2012 David Anderson
25.7 - *
25.8 - * This file is part of JITCraft.
25.9 - *
25.10 - * JITCraft is free software: you can redistribute it and/or modify it under
25.11 - * the terms of the GNU General Public License as published by the Free
25.12 - * Software Foundation, either version 3 of the License, or (at your option)
25.13 - * any later version.
25.14 - *
25.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
25.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
25.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
25.18 - *
25.19 - * You should have received a copy of the GNU General Public License along with
25.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
25.21 - */
25.22 -#include <stdlib.h>
25.23 -#include "Opcodes.h"
25.24 -#include "Utility.h"
25.25 -#include "Code.h"
25.26 -#include "Zone.h"
25.27 -#include "Array.h"
25.28 -#include "Strings.h"
25.29 -#include "CompactBuffer.h"
25.30 -#include "Structures.h"
25.31 -#include "Modules.h"
25.32 -#include "Heap-inl.h"
25.33 -
25.34 -using namespace ke;
25.35 -
25.36 -OpInfo ke::OpcodeInfo[] =
25.37 -{
25.38 -#define OPDEF(name, text, length, uses, defs) \
25.39 - {text, length, uses, defs},
25.40 -#include "Opcodes.tbl"
25.41 -#undef OPDEF
25.42 -};
25.43 -
25.44 -Code *
25.45 -Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
25.46 - Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
25.47 - unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap)
25.48 -{
25.49 - Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
25.50 - if (!code)
25.51 - return NULL;
25.52 -
25.53 - code->bytecode_ = bytecode;
25.54 - code->locals_ = locals;
25.55 - code->objects_ = objects;
25.56 - code->maxStackDepth_ = maxStackDepth;
25.57 - code->module_ = NULL;
25.58 - code->safepoints_ = safepoints;
25.59 - code->sourcemap_ = sourcemap;
25.60 - code->lineNumber_ = 0;
25.61 - code->strings_ = strings;
25.62 - code->maxLoopDepth_ = maxLoopDepth;
25.63 - return code;
25.64 -}
25.65 -
25.66 -static int
25.67 -CompareSafepoints(const void *a, const void *b)
25.68 -{
25.69 - const unsigned *sa = reinterpret_cast<const unsigned *>(a);
25.70 - const unsigned *sb = reinterpret_cast<const unsigned *>(b);
25.71 - if (*sa > *sb)
25.72 - return 1;
25.73 - if (*sa == *sb)
25.74 - return 0;
25.75 - return -1;
25.76 -}
25.77 -
25.78 -uint8 *
25.79 -Code::safepointAt(unsigned pcOffset)
25.80 -{
25.81 - // Only specific opcodes may have safepoints. Asking for a safepoint at
25.82 - // any other position indicates a failure to mark that position as a
25.83 - // safepoint, which is a bug.
25.84 -#ifndef NDEBUG
25.85 - Opcode op = Opcode(*(start() + pcOffset));
25.86 - assert(op == OP_CALL ||
25.87 - op == OP_NEWFIXED ||
25.88 - op == OP_NEWEMPTY ||
25.89 - op == OP_NEWSIZED ||
25.90 - op == OP_VARREF_LIFO ||
25.91 - op == OP_ARGREF_LIFO ||
25.92 - op == OP_SLOTREF_LIFO ||
25.93 - op == OP_COPYARRAY ||
25.94 - op == OP_CALLNATIVE ||
25.95 - op == OP_PUBLIC);
25.96 -#endif
25.97 -
25.98 - if (!safepoints_)
25.99 - return NULL;
25.100 -
25.101 - size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth());
25.102 - assert(!(safepoints_->length() % bytesPerSafepoint));
25.103 -
25.104 - size_t count = safepoints_->length() / bytesPerSafepoint;
25.105 -
25.106 - void *result = bsearch(&pcOffset,
25.107 - safepoints_->raw(),
25.108 - count,
25.109 - bytesPerSafepoint,
25.110 - CompareSafepoints);
25.111 -
25.112 - if (!result)
25.113 - return NULL;
25.114 -
25.115 - assert(*reinterpret_cast<unsigned *>(result) == pcOffset);
25.116 -
25.117 - return Address(result) + sizeof(unsigned);
25.118 -}
25.119 -
25.120 -SourcePosition
25.121 -Code::pcToSource(unsigned pc)
25.122 -{
25.123 - assert(pc < bytecode_->length());
25.124 -
25.125 - CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length());
25.126 -
25.127 - unsigned line = 1;
25.128 - unsigned col = 0;
25.129 - unsigned curPc = 0;
25.130 - while (!reader.done()) {
25.131 - curPc += reader.readUint32();
25.132 - if (curPc > pc)
25.133 - break;
25.134 -
25.135 - line = reader.readUint32();
25.136 - col = reader.readUint32();
25.137 - }
25.138 -
25.139 - return SourcePosition(lineNumber_ + line, col);
25.140 -}
25.141 -
25.142 -// All jumps must be the same length.
25.143 -STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
25.144 -STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
25.145 -
25.146 -void
25.147 -ke::Disassemble(Code *code, FILE *fp)
25.148 -{
25.149 - bytecode *pc = code->start();
25.150 - for (;;) {
25.151 - Opcode op = Opcode(*pc);
25.152 -
25.153 - fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name);
25.154 -
25.155 - switch (op) {
25.156 - case OP_NOP:
25.157 - case OP_RETURN:
25.158 - case OP_RETURNVOID:
25.159 - case OP_ADD:
25.160 - case OP_SUB:
25.161 - case OP_MUL:
25.162 - case OP_DIV:
25.163 - case OP_ADD_F:
25.164 - case OP_SUB_F:
25.165 - case OP_MUL_F:
25.166 - case OP_DIV_F:
25.167 - case OP_CVT_I2F:
25.168 - case OP_CVT_I2B:
25.169 - case OP_POP:
25.170 - case OP_GETELEM:
25.171 - case OP_SETELEM:
25.172 - case OP_SHL:
25.173 - case OP_SHR:
25.174 - case OP_USHR:
25.175 - case OP_BITAND:
25.176 - case OP_BITOR:
25.177 - case OP_BITXOR:
25.178 - case OP_GETREF_I:
25.179 - case OP_SETREF_I:
25.180 - case OP_GETREF_F:
25.181 - case OP_SETREF_F:
25.182 - case OP_SLOTREF_LIFO:
25.183 - case OP_COPYARRAY:
25.184 - case OP_COPYSTRUCT:
25.185 - case OP_DUP:
25.186 - case OP_DUP2:
25.187 - case OP_SWAP:
25.188 - case OP_ROLL3:
25.189 - case OP_PICK2:
25.190 - case OP_PICK3:
25.191 - case OP_CALL:
25.192 - case OP_LT:
25.193 - case OP_LE:
25.194 - case OP_GE:
25.195 - case OP_GT:
25.196 - case OP_EQ:
25.197 - case OP_NE:
25.198 - case OP_LT_F:
25.199 - case OP_LE_F:
25.200 - case OP_GE_F:
25.201 - case OP_GT_F:
25.202 - case OP_EQ_F:
25.203 - case OP_NE_F:
25.204 - case OP_BITNOT:
25.205 - case OP_NOT:
25.206 - case OP_NOT_F:
25.207 - case OP_NEG:
25.208 - case OP_NEG_F:
25.209 - case OP_MOD:
25.210 - case OP_BITCAST:
25.211 - case OP_TRUE:
25.212 - case OP_FALSE:
25.213 - case OP_SIZEOF:
25.214 - case OP_PUBLIC:
25.215 - case OP_LEAVELOOP:
25.216 - case OP_DUPARRAY:
25.217 - case OP_DEPARRAY:
25.218 - break;
25.219 -
25.220 - case OP_ENTERLOOP:
25.221 - if (pc[1])
25.222 - fprintf(fp, "; lifo region");
25.223 - break;
25.224 -
25.225 - case OP_STOP:
25.226 - fprintf(fp, "\n");
25.227 - break;
25.228 -
25.229 - case OP_INT:
25.230 - fprintf(fp, "%d", READ_INT32(pc));
25.231 - break;
25.232 -
25.233 - case OP_FLOAT:
25.234 - fprintf(fp, "%f", READ_FLOAT(pc));
25.235 - break;
25.236 -
25.237 - case OP_JT:
25.238 - case OP_JF:
25.239 - case OP_JUMP:
25.240 - case OP_CONTINUE:
25.241 - case OP_BREAK:
25.242 - fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
25.243 - break;
25.244 -
25.245 - case OP_NEWFIXED:
25.246 - case OP_NEWEMPTY:
25.247 - case OP_NEWSIZED:
25.248 - {
25.249 - Heap::Tenure tenure = (Heap::Tenure)pc[1];
25.250 - //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1)));
25.251 - if (tenure == Heap::Tenure_Stack)
25.252 - fprintf(fp, " ; lifo");
25.253 - else if (tenure == Heap::Tenure_Old)
25.254 - fprintf(fp, " ; pretenured");
25.255 - else if (tenure == Heap::Tenure_Default)
25.256 - fprintf(fp, " ; newborn");
25.257 - break;
25.258 - }
25.259 -
25.260 - case OP_NEWSTRUCT:
25.261 - {
25.262 - Heap::Tenure tenure = (Heap::Tenure)pc[1];
25.263 - StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1)));
25.264 - fprintf(fp, "%s", StructType::cast(map->type())->name()->chars());
25.265 - if (tenure == Heap::Tenure_Stack)
25.266 - fprintf(fp, " ; lifo");
25.267 - else if (tenure == Heap::Tenure_Old)
25.268 - fprintf(fp, " ; pretenured");
25.269 - else if (tenure == Heap::Tenure_Default)
25.270 - fprintf(fp, " ; newborn");
25.271 - break;
25.272 - }
25.273 -
25.274 - case OP_GETLOCAL:
25.275 - case OP_SETLOCAL:
25.276 - case OP_GETARG:
25.277 - case OP_SETARG:
25.278 - case OP_SAVELIFO:
25.279 - case OP_UNWINDLIFO:
25.280 - case OP_VARREF_LIFO:
25.281 - case OP_ARGREF_LIFO:
25.282 - case OP_OBJECT:
25.283 - case OP_GETFIELD:
25.284 - case OP_SETFIELD:
25.285 - fprintf(fp, "%u", READ_UINT32(pc));
25.286 - break;
25.287 -
25.288 - case OP_CALLNATIVE:
25.289 - {
25.290 - unsigned argc = READ_UINT32(pc);
25.291 - fprintf(fp, " ; %u args", argc);
25.292 - break;
25.293 - }
25.294 -
25.295 - case OP_TABLESWITCH:
25.296 - {
25.297 - int low = READ_TABLESWITCH_LOW(pc);
25.298 - int high = READ_TABLESWITCH_HIGH(pc);
25.299 - fprintf(fp, "%d, %d\n", low, high);
25.300 - break;
25.301 - }
25.302 -
25.303 - case OP_GETGLOBAL:
25.304 - case OP_SETGLOBAL:
25.305 - {
25.306 - unsigned index = READ_UINT32(pc);
25.307 - fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars());
25.308 - break;
25.309 - }
25.310 -
25.311 - case OP_IMPORT:
25.312 - {
25.313 - unsigned index = READ_UINT32(pc);
25.314 - FixedArray *path = code->module()->importPathAt(index);
25.315 - fprintf(fp, " ; ");
25.316 - for (unsigned i = 0; i < path->length(); i++) {
25.317 - fprintf(fp, "%s", String::cast(path->at(i))->chars());
25.318 - if (i != path->length() - 1)
25.319 - fprintf(fp, ".");
25.320 - }
25.321 - break;
25.322 - }
25.323 -
25.324 - default:
25.325 - // Unknown opcode!
25.326 - assert(false);
25.327 - return;
25.328 - }
25.329 -
25.330 - if (op == OP_STOP)
25.331 - break;
25.332 -
25.333 - fprintf(fp, "\n");
25.334 - pc += OpcodeInfo[op].length;
25.335 - assert(pc < code->start() + code->length());
25.336 - }
25.337 -
25.338 - fprintf(fp, "\nSafepoints:\n");
25.339 - ByteArray *safepoints = code->safepoints();
25.340 - if (safepoints) {
25.341 - size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth());
25.342 - for (size_t i = 0; i < nsafepoints; i++) {
25.343 - Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i;
25.344 - fprintf(fp, "%4d: ", *reinterpret_cast<unsigned *>(address));
25.345 - unsigned char *bits = (unsigned char *)(address + sizeof(unsigned));
25.346 - for (unsigned j = 0; j < code->maxStackDepth(); j++) {
25.347 - if (bits[j / 8] & (1 << (j % 8)))
25.348 - fprintf(fp, "%d ", j);
25.349 - }
25.350 - fprintf(fp, "\n");
25.351 - }
25.352 - }
25.353 -}
25.354 +/* vim: set ts=4 sw=4 tw=99 et:
25.355 + *
25.356 + * Copyright (C) 2012 David Anderson
25.357 + *
25.358 + * This file is part of JITCraft.
25.359 + *
25.360 + * JITCraft is free software: you can redistribute it and/or modify it under
25.361 + * the terms of the GNU General Public License as published by the Free
25.362 + * Software Foundation, either version 3 of the License, or (at your option)
25.363 + * any later version.
25.364 + *
25.365 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
25.366 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
25.367 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
25.368 + *
25.369 + * You should have received a copy of the GNU General Public License along with
25.370 + * JITCraft. If not, see http://www.gnu.org/licenses/.
25.371 + */
25.372 +#include <stdlib.h>
25.373 +#include "Opcodes.h"
25.374 +#include "Utility.h"
25.375 +#include "Code.h"
25.376 +#include "Zone.h"
25.377 +#include "Array.h"
25.378 +#include "Strings.h"
25.379 +#include "CompactBuffer.h"
25.380 +#include "Structures.h"
25.381 +#include "Modules.h"
25.382 +#include "Heap-inl.h"
25.383 +
25.384 +using namespace ke;
25.385 +
25.386 +OpInfo ke::OpcodeInfo[] =
25.387 +{
25.388 +#define OPDEF(name, text, length, uses, defs) \
25.389 + {text, length, uses, defs},
25.390 +#include "Opcodes.tbl"
25.391 +#undef OPDEF
25.392 +};
25.393 +
25.394 +Code *
25.395 +Code::New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
25.396 + Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
25.397 + unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap)
25.398 +{
25.399 + Local<Code> code(zone, Code::cast(zone->allocate(MapKind_Code, sizeof(Code), Heap::Tenure_Old)));
25.400 + if (!code)
25.401 + return NULL;
25.402 +
25.403 + code->bytecode_ = bytecode;
25.404 + code->locals_ = locals;
25.405 + code->objects_ = objects;
25.406 + code->maxStackDepth_ = maxStackDepth;
25.407 + code->module_ = NULL;
25.408 + code->safepoints_ = safepoints;
25.409 + code->sourcemap_ = sourcemap;
25.410 + code->lineNumber_ = 0;
25.411 + code->strings_ = strings;
25.412 + code->maxLoopDepth_ = maxLoopDepth;
25.413 + return code;
25.414 +}
25.415 +
25.416 +static int
25.417 +CompareSafepoints(const void *a, const void *b)
25.418 +{
25.419 + const unsigned *sa = reinterpret_cast<const unsigned *>(a);
25.420 + const unsigned *sb = reinterpret_cast<const unsigned *>(b);
25.421 + if (*sa > *sb)
25.422 + return 1;
25.423 + if (*sa == *sb)
25.424 + return 0;
25.425 + return -1;
25.426 +}
25.427 +
25.428 +uint8 *
25.429 +Code::safepointAt(unsigned pcOffset)
25.430 +{
25.431 + // Only specific opcodes may have safepoints. Asking for a safepoint at
25.432 + // any other position indicates a failure to mark that position as a
25.433 + // safepoint, which is a bug.
25.434 +#ifndef NDEBUG
25.435 + Opcode op = Opcode(*(start() + pcOffset));
25.436 + assert(op == OP_CALL ||
25.437 + op == OP_NEWFIXED ||
25.438 + op == OP_NEWEMPTY ||
25.439 + op == OP_NEWSIZED ||
25.440 + op == OP_VARREF_LIFO ||
25.441 + op == OP_ARGREF_LIFO ||
25.442 + op == OP_SLOTREF_LIFO ||
25.443 + op == OP_COPYARRAY ||
25.444 + op == OP_CALLNATIVE ||
25.445 + op == OP_PUBLIC);
25.446 +#endif
25.447 +
25.448 + if (!safepoints_)
25.449 + return NULL;
25.450 +
25.451 + size_t bytesPerSafepoint = BytesPerSafepoint(maxStackDepth());
25.452 + assert(!(safepoints_->length() % bytesPerSafepoint));
25.453 +
25.454 + size_t count = safepoints_->length() / bytesPerSafepoint;
25.455 +
25.456 + void *result = bsearch(&pcOffset,
25.457 + safepoints_->raw(),
25.458 + count,
25.459 + bytesPerSafepoint,
25.460 + CompareSafepoints);
25.461 +
25.462 + if (!result)
25.463 + return NULL;
25.464 +
25.465 + assert(*reinterpret_cast<unsigned *>(result) == pcOffset);
25.466 +
25.467 + return Address(result) + sizeof(unsigned);
25.468 +}
25.469 +
25.470 +SourcePosition
25.471 +Code::pcToSource(unsigned pc)
25.472 +{
25.473 + assert(pc < bytecode_->length());
25.474 +
25.475 + CompactBufferReader reader(sourcemap_->raw(), sourcemap_->raw() + sourcemap_->length());
25.476 +
25.477 + unsigned line = 1;
25.478 + unsigned col = 0;
25.479 + unsigned curPc = 0;
25.480 + while (!reader.done()) {
25.481 + curPc += reader.readUint32();
25.482 + if (curPc > pc)
25.483 + break;
25.484 +
25.485 + line = reader.readUint32();
25.486 + col = reader.readUint32();
25.487 + }
25.488 +
25.489 + return SourcePosition(lineNumber_ + line, col);
25.490 +}
25.491 +
25.492 +// All jumps must be the same length.
25.493 +STATIC_ASSERT(OP_JT_LENGTH == OP_JUMP_LENGTH);
25.494 +STATIC_ASSERT(OP_JF_LENGTH == OP_JUMP_LENGTH);
25.495 +
25.496 +void
25.497 +ke::Disassemble(Code *code, FILE *fp)
25.498 +{
25.499 + bytecode *pc = code->start();
25.500 + for (;;) {
25.501 + Opcode op = Opcode(*pc);
25.502 +
25.503 + fprintf(fp, "%-4d %s ", int(pc - code->start()), OpcodeInfo[op].name);
25.504 +
25.505 + switch (op) {
25.506 + case OP_NOP:
25.507 + case OP_RETURN:
25.508 + case OP_RETURNVOID:
25.509 + case OP_ADD:
25.510 + case OP_SUB:
25.511 + case OP_MUL:
25.512 + case OP_DIV:
25.513 + case OP_ADD_F:
25.514 + case OP_SUB_F:
25.515 + case OP_MUL_F:
25.516 + case OP_DIV_F:
25.517 + case OP_CVT_I2F:
25.518 + case OP_CVT_I2B:
25.519 + case OP_POP:
25.520 + case OP_GETELEM:
25.521 + case OP_SETELEM:
25.522 + case OP_SHL:
25.523 + case OP_SHR:
25.524 + case OP_USHR:
25.525 + case OP_BITAND:
25.526 + case OP_BITOR:
25.527 + case OP_BITXOR:
25.528 + case OP_GETREF_I:
25.529 + case OP_SETREF_I:
25.530 + case OP_GETREF_F:
25.531 + case OP_SETREF_F:
25.532 + case OP_SLOTREF_LIFO:
25.533 + case OP_COPYARRAY:
25.534 + case OP_COPYSTRUCT:
25.535 + case OP_DUP:
25.536 + case OP_DUP2:
25.537 + case OP_SWAP:
25.538 + case OP_ROLL3:
25.539 + case OP_PICK2:
25.540 + case OP_PICK3:
25.541 + case OP_CALL:
25.542 + case OP_LT:
25.543 + case OP_LE:
25.544 + case OP_GE:
25.545 + case OP_GT:
25.546 + case OP_EQ:
25.547 + case OP_NE:
25.548 + case OP_LT_F:
25.549 + case OP_LE_F:
25.550 + case OP_GE_F:
25.551 + case OP_GT_F:
25.552 + case OP_EQ_F:
25.553 + case OP_NE_F:
25.554 + case OP_BITNOT:
25.555 + case OP_NOT:
25.556 + case OP_NOT_F:
25.557 + case OP_NEG:
25.558 + case OP_NEG_F:
25.559 + case OP_MOD:
25.560 + case OP_BITCAST:
25.561 + case OP_TRUE:
25.562 + case OP_FALSE:
25.563 + case OP_SIZEOF:
25.564 + case OP_PUBLIC:
25.565 + case OP_LEAVELOOP:
25.566 + case OP_DUPARRAY:
25.567 + case OP_DEPARRAY:
25.568 + break;
25.569 +
25.570 + case OP_ENTERLOOP:
25.571 + if (pc[1])
25.572 + fprintf(fp, "; lifo region");
25.573 + break;
25.574 +
25.575 + case OP_STOP:
25.576 + fprintf(fp, "\n");
25.577 + break;
25.578 +
25.579 + case OP_INT:
25.580 + fprintf(fp, "%d", READ_INT32(pc));
25.581 + break;
25.582 +
25.583 + case OP_FLOAT:
25.584 + fprintf(fp, "%f", READ_FLOAT(pc));
25.585 + break;
25.586 +
25.587 + case OP_JT:
25.588 + case OP_JF:
25.589 + case OP_JUMP:
25.590 + case OP_CONTINUE:
25.591 + case OP_BREAK:
25.592 + fprintf(fp, "%u (%+d)", unsigned((pc + READ_INT32(pc)) - code->start()), READ_INT32(pc));
25.593 + break;
25.594 +
25.595 + case OP_NEWFIXED:
25.596 + case OP_NEWEMPTY:
25.597 + case OP_NEWSIZED:
25.598 + {
25.599 + Heap::Tenure tenure = (Heap::Tenure)pc[1];
25.600 + //ArrayMap *map = ArrayMap::cast(code->map(READ_UINT32(pc + 1)));
25.601 + if (tenure == Heap::Tenure_Stack)
25.602 + fprintf(fp, " ; lifo");
25.603 + else if (tenure == Heap::Tenure_Old)
25.604 + fprintf(fp, " ; pretenured");
25.605 + else if (tenure == Heap::Tenure_Default)
25.606 + fprintf(fp, " ; newborn");
25.607 + break;
25.608 + }
25.609 +
25.610 + case OP_NEWSTRUCT:
25.611 + {
25.612 + Heap::Tenure tenure = (Heap::Tenure)pc[1];
25.613 + StructMap *map = StructMap::cast(code->map(READ_UINT32(pc + 1)));
25.614 + fprintf(fp, "%s", StructType::cast(map->type())->name()->chars());
25.615 + if (tenure == Heap::Tenure_Stack)
25.616 + fprintf(fp, " ; lifo");
25.617 + else if (tenure == Heap::Tenure_Old)
25.618 + fprintf(fp, " ; pretenured");
25.619 + else if (tenure == Heap::Tenure_Default)
25.620 + fprintf(fp, " ; newborn");
25.621 + break;
25.622 + }
25.623 +
25.624 + case OP_GETLOCAL:
25.625 + case OP_SETLOCAL:
25.626 + case OP_GETARG:
25.627 + case OP_SETARG:
25.628 + case OP_SAVELIFO:
25.629 + case OP_UNWINDLIFO:
25.630 + case OP_VARREF_LIFO:
25.631 + case OP_ARGREF_LIFO:
25.632 + case OP_OBJECT:
25.633 + case OP_GETFIELD:
25.634 + case OP_SETFIELD:
25.635 + fprintf(fp, "%u", READ_UINT32(pc));
25.636 + break;
25.637 +
25.638 + case OP_CALLNATIVE:
25.639 + {
25.640 + unsigned argc = READ_UINT32(pc);
25.641 + fprintf(fp, " ; %u args", argc);
25.642 + break;
25.643 + }
25.644 +
25.645 + case OP_TABLESWITCH:
25.646 + {
25.647 + int low = READ_TABLESWITCH_LOW(pc);
25.648 + int high = READ_TABLESWITCH_HIGH(pc);
25.649 + fprintf(fp, "%d, %d\n", low, high);
25.650 + break;
25.651 + }
25.652 +
25.653 + case OP_GETGLOBAL:
25.654 + case OP_SETGLOBAL:
25.655 + {
25.656 + unsigned index = READ_UINT32(pc);
25.657 + fprintf(fp, "%s", String::cast(code->strings()->at(index))->chars());
25.658 + break;
25.659 + }
25.660 +
25.661 + case OP_IMPORT:
25.662 + {
25.663 + unsigned index = READ_UINT32(pc);
25.664 + FixedArray *path = code->module()->importPathAt(index);
25.665 + fprintf(fp, " ; ");
25.666 + for (unsigned i = 0; i < path->length(); i++) {
25.667 + fprintf(fp, "%s", String::cast(path->at(i))->chars());
25.668 + if (i != path->length() - 1)
25.669 + fprintf(fp, ".");
25.670 + }
25.671 + break;
25.672 + }
25.673 +
25.674 + default:
25.675 + // Unknown opcode!
25.676 + assert(false);
25.677 + return;
25.678 + }
25.679 +
25.680 + if (op == OP_STOP)
25.681 + break;
25.682 +
25.683 + fprintf(fp, "\n");
25.684 + pc += OpcodeInfo[op].length;
25.685 + assert(pc < code->start() + code->length());
25.686 + }
25.687 +
25.688 + fprintf(fp, "\nSafepoints:\n");
25.689 + ByteArray *safepoints = code->safepoints();
25.690 + if (safepoints) {
25.691 + size_t nsafepoints = safepoints->length() / Code::BytesPerSafepoint(code->maxStackDepth());
25.692 + for (size_t i = 0; i < nsafepoints; i++) {
25.693 + Address address = safepoints->raw() + Code::BytesPerSafepoint(code->maxStackDepth()) * i;
25.694 + fprintf(fp, "%4d: ", *reinterpret_cast<unsigned *>(address));
25.695 + unsigned char *bits = (unsigned char *)(address + sizeof(unsigned));
25.696 + for (unsigned j = 0; j < code->maxStackDepth(); j++) {
25.697 + if (bits[j / 8] & (1 << (j % 8)))
25.698 + fprintf(fp, "%d ", j);
25.699 + }
25.700 + fprintf(fp, "\n");
25.701 + }
25.702 + }
25.703 +}
26.1 --- a/src/Opcodes.h Mon Jun 10 00:46:29 2013 +0100
26.2 +++ b/src/Opcodes.h Mon Jun 10 01:04:43 2013 +0100
26.3 @@ -1,113 +1,113 @@
26.4 -/* vim: set ts=4 sw=4 tw=99 et:
26.5 - *
26.6 - * Copyright (C) 2012 David Anderson
26.7 - *
26.8 - * This file is part of SourcePawn.
26.9 - *
26.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
26.11 - * the terms of the GNU General Public License as published by the Free
26.12 - * Software Foundation, either version 3 of the License, or (at your option)
26.13 - * any later version.
26.14 - *
26.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
26.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
26.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
26.18 - *
26.19 - * You should have received a copy of the GNU General Public License along with
26.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
26.21 - */
26.22 -#ifndef _include_opcodes_h_
26.23 -#define _include_opcodes_h_
26.24 -
26.25 -#include <assert.h>
26.26 -#include <stdio.h>
26.27 -
26.28 -namespace ke {
26.29 -
26.30 -struct SourcePosition
26.31 -{
26.32 - int line;
26.33 - int col;
26.34 -
26.35 - SourcePosition()
26.36 - : line(-1),
26.37 - col(-1)
26.38 - {
26.39 - }
26.40 -
26.41 - SourcePosition(unsigned line, unsigned col)
26.42 - : line(line),
26.43 - col(col)
26.44 - {
26.45 - }
26.46 -};
26.47 -
26.48 -enum Opcode
26.49 -{
26.50 -#define OPDEF(name, text, length, uses, defs) \
26.51 - name,
26.52 -#include "Opcodes.tbl"
26.53 -#undef OPDEF
26.54 - OPCODES_TOTAL
26.55 -};
26.56 -
26.57 -#define OPDEF(name, text, length, uses, defs) \
26.58 -static const unsigned name##_LENGTH = length;
26.59 -#include "Opcodes.tbl"
26.60 -#undef OPDEF
26.61 -
26.62 -struct OpInfo
26.63 -{
26.64 - const char *name;
26.65 - int length;
26.66 - int nuses;
26.67 - int ndefs;
26.68 -};
26.69 -
26.70 -typedef unsigned char bytecode;
26.71 -
26.72 -extern OpInfo OpcodeInfo[];
26.73 -
26.74 -static const unsigned MAX_TABLESWITCH_ENTRIES = 256;
26.75 -
26.76 -static inline unsigned
26.77 -TableSwitchEntries(int low, int high)
26.78 -{
26.79 - return unsigned(high - low) + 1;
26.80 -}
26.81 -
26.82 -static inline int
26.83 -READ_INT32(bytecode *pc)
26.84 -{
26.85 - return *reinterpret_cast<int *>(pc + 1);
26.86 -}
26.87 -static inline unsigned
26.88 -READ_UINT32(bytecode *pc)
26.89 -{
26.90 - return *reinterpret_cast<unsigned *>(pc + 1);
26.91 -}
26.92 -static inline float
26.93 -READ_FLOAT(bytecode *pc)
26.94 -{
26.95 - return *reinterpret_cast<float *>(pc + 1);
26.96 -}
26.97 -
26.98 -static inline int
26.99 -READ_TABLESWITCH_LOW(bytecode *pc)
26.100 -{
26.101 - return READ_INT32(pc);
26.102 -}
26.103 -
26.104 -static inline int
26.105 -READ_TABLESWITCH_HIGH(bytecode *pc)
26.106 -{
26.107 - return READ_INT32(pc + sizeof(int));
26.108 -}
26.109 -
26.110 -class Code;
26.111 -
26.112 -void Disassemble(Code *code, FILE *fp);
26.113 -
26.114 -}
26.115 -
26.116 -#endif // _include_opcodes_h_
26.117 +/* vim: set ts=4 sw=4 tw=99 et:
26.118 + *
26.119 + * Copyright (C) 2012 David Anderson
26.120 + *
26.121 + * This file is part of SourcePawn.
26.122 + *
26.123 + * SourcePawn is free software: you can redistribute it and/or modify it under
26.124 + * the terms of the GNU General Public License as published by the Free
26.125 + * Software Foundation, either version 3 of the License, or (at your option)
26.126 + * any later version.
26.127 + *
26.128 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
26.129 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
26.130 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
26.131 + *
26.132 + * You should have received a copy of the GNU General Public License along with
26.133 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
26.134 + */
26.135 +#ifndef _include_opcodes_h_
26.136 +#define _include_opcodes_h_
26.137 +
26.138 +#include <assert.h>
26.139 +#include <stdio.h>
26.140 +
26.141 +namespace ke {
26.142 +
26.143 +struct SourcePosition
26.144 +{
26.145 + int line;
26.146 + int col;
26.147 +
26.148 + SourcePosition()
26.149 + : line(-1),
26.150 + col(-1)
26.151 + {
26.152 + }
26.153 +
26.154 + SourcePosition(unsigned line, unsigned col)
26.155 + : line(line),
26.156 + col(col)
26.157 + {
26.158 + }
26.159 +};
26.160 +
26.161 +enum Opcode
26.162 +{
26.163 +#define OPDEF(name, text, length, uses, defs) \
26.164 + name,
26.165 +#include "Opcodes.tbl"
26.166 +#undef OPDEF
26.167 + OPCODES_TOTAL
26.168 +};
26.169 +
26.170 +#define OPDEF(name, text, length, uses, defs) \
26.171 +static const unsigned name##_LENGTH = length;
26.172 +#include "Opcodes.tbl"
26.173 +#undef OPDEF
26.174 +
26.175 +struct OpInfo
26.176 +{
26.177 + const char *name;
26.178 + int length;
26.179 + int nuses;
26.180 + int ndefs;
26.181 +};
26.182 +
26.183 +typedef unsigned char bytecode;
26.184 +
26.185 +extern OpInfo OpcodeInfo[];
26.186 +
26.187 +static const unsigned MAX_TABLESWITCH_ENTRIES = 256;
26.188 +
26.189 +static inline unsigned
26.190 +TableSwitchEntries(int low, int high)
26.191 +{
26.192 + return unsigned(high - low) + 1;
26.193 +}
26.194 +
26.195 +static inline int
26.196 +READ_INT32(bytecode *pc)
26.197 +{
26.198 + return *reinterpret_cast<int *>(pc + 1);
26.199 +}
26.200 +static inline unsigned
26.201 +READ_UINT32(bytecode *pc)
26.202 +{
26.203 + return *reinterpret_cast<unsigned *>(pc + 1);
26.204 +}
26.205 +static inline float
26.206 +READ_FLOAT(bytecode *pc)
26.207 +{
26.208 + return *reinterpret_cast<float *>(pc + 1);
26.209 +}
26.210 +
26.211 +static inline int
26.212 +READ_TABLESWITCH_LOW(bytecode *pc)
26.213 +{
26.214 + return READ_INT32(pc);
26.215 +}
26.216 +
26.217 +static inline int
26.218 +READ_TABLESWITCH_HIGH(bytecode *pc)
26.219 +{
26.220 + return READ_INT32(pc + sizeof(int));
26.221 +}
26.222 +
26.223 +class Code;
26.224 +
26.225 +void Disassemble(Code *code, FILE *fp);
26.226 +
26.227 +}
26.228 +
26.229 +#endif // _include_opcodes_h_
27.1 --- a/src/Packages.cpp Mon Jun 10 00:46:29 2013 +0100
27.2 +++ b/src/Packages.cpp Mon Jun 10 01:04:43 2013 +0100
27.3 @@ -1,226 +1,226 @@
27.4 -/*
27.5 - * Copyright (C) 2012 David Anderson
27.6 - *
27.7 - * This file is part of SourcePawn.
27.8 - *
27.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
27.10 - * the terms of the GNU General Public License as published by the Free
27.11 - * Software Foundation, either version 3 of the License, or (at your option)
27.12 - * any later version.
27.13 - *
27.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
27.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
27.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
27.17 - *
27.18 - * You should have received a copy of the GNU General Public License along with
27.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
27.20 - */
27.21 -#include <string.h>
27.22 -#include "Zone.h"
27.23 -#include "Heap.h"
27.24 -#include "Strings.h"
27.25 -#include "Modules.h"
27.26 -#include "Packages.h"
27.27 -#include "FileSystem.h"
27.28 -#include "List.h"
27.29 -#include "Heap-inl.h"
27.30 -#include "Handles-inl.h"
27.31 -
27.32 -using namespace ke;
27.33 -
27.34 -Package *
27.35 -Package::NewNormalized(Zone *zone, Handle<Package> parent, Handle<String> path, Handle<String> name, unsigned flags)
27.36 -{
27.37 - Local<Package> package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old)));
27.38 - if (!package)
27.39 - return NULL;
27.40 -
27.41 - // :TODO: assert path, name are atoms.
27.42 -
27.43 - package->flags_ = flags;
27.44 - package->name_ = name;
27.45 - package->parent_ = parent;
27.46 - package->path_ = path;
27.47 - package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL;
27.48 -
27.49 - return package;
27.50 -}
27.51 -
27.52 -Package *
27.53 -Package::New(Zone *zone, Handle<Package> parent, const char *path, Handle<String> name, unsigned flags)
27.54 -{
27.55 - Local<String> strpath(zone, zone->makeSymbol(path));
27.56 - if (!strpath)
27.57 - return NULL;
27.58 -
27.59 - return Package::NewNormalized(zone, parent, strpath, name, flags);
27.60 -}
27.61 -
27.62 -bool
27.63 -Package::add(Zone *zone, Handle<Importable> obj)
27.64 -{
27.65 - Local<Package> pkg(zone, this);
27.66 -
27.67 - assert(obj->parent() == pkg);
27.68 -
27.69 - if (!pkg->contents_) {
27.70 - pkg->contents_ = List<Importable>::New(zone);
27.71 - if (!pkg->contents_)
27.72 - return false;
27.73 - }
27.74 -
27.75 -#ifndef NDEBUG
27.76 - // Assert no duplicate names.
27.77 - for (unsigned i = 0; i < pkg->contents_->length(); i++)
27.78 - assert(pkg->contents_->at(i)->name() != obj->name());
27.79 -#endif
27.80 -
27.81 - if (!pkg->contents_->append(zone, obj))
27.82 - return false;
27.83 -
27.84 - return true;
27.85 -}
27.86 -
27.87 -Importable *
27.88 -Package::import(Handle<String> name)
27.89 -{
27.90 - if (!contents_)
27.91 - return NULL;
27.92 -
27.93 - for (unsigned i = 0; i < contents_->length(); i++) {
27.94 - Importable *obj = contents_->at(i);
27.95 - if (obj->isPackage() && Package::cast(obj)->name() == name)
27.96 - return obj;
27.97 - if (obj->isModule() && Module::cast(obj)->name() == name)
27.98 - return obj;
27.99 - }
27.100 -
27.101 - return NULL;
27.102 -}
27.103 -
27.104 -PackageCache::PackageCache(Zone *zone)
27.105 - : zone_(zone)
27.106 -{
27.107 -}
27.108 -
27.109 -bool
27.110 -PackageCache::initialize()
27.111 -{
27.112 - return true;
27.113 -}
27.114 -
27.115 -void
27.116 -PackageCache::accept(VirtualObjectVisitor *visitor)
27.117 -{
27.118 - for (size_t i = 0; i < roots_.length(); i++)
27.119 - visitor->visit(roots_[i].address());
27.120 -}
27.121 -
27.122 -bool
27.123 -PackageCache::checkfs(Handle<Package> package, PathComponent *path, Importable **out)
27.124 -{
27.125 - AutoFree<char> left(strdup(package->path()->chars()));
27.126 - AutoFree<char> right(strdup(path->name->chars()));
27.127 - AutoFree<char> result;
27.128 -
27.129 - if (!JoinPaths(zone_, result, *left, *right))
27.130 - return false;
27.131 -
27.132 - OS::PathType type = OS::InspectPath(*result);
27.133 - if (type == OS::Path_Folder) {
27.134 - // If there is a folder matching this path, create a new subpackage,
27.135 - // and then either return it (if this is the last link), or keep
27.136 - // trying to import the rest of the path.
27.137 - Local<String> strpath(zone_, zone_->makeSymbol(*result));
27.138 - Local<Package> subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal));
27.139 - if (!subpackage)
27.140 - return false;
27.141 - if (!path->next) {
27.142 - *out = subpackage;
27.143 - return true;
27.144 - }
27.145 - return import(subpackage, path->next, out);
27.146 - }
27.147 -
27.148 - // Otherwise, look for a file ending in ".sp".
27.149 - AutoFree<char> filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1));
27.150 - if (!*filepath)
27.151 - return false;
27.152 -
27.153 - strcpy(*filepath, *result);
27.154 - strcat(*filepath, ".sp");
27.155 -
27.156 - type = OS::InspectPath(*filepath);
27.157 - if (type != OS::Path_File)
27.158 - return true;
27.159 -
27.160 - // Create a new, empty module.
27.161 - Local<String> strpath(zone_, zone_->makeSymbol(*filepath));
27.162 - if (!strpath)
27.163 - return false;
27.164 -
27.165 - Local<Module> module(zone_, Module::New(zone_, package, strpath, path->name));
27.166 - if (!module || !package->add(zone_, module))
27.167 - return false;
27.168 -
27.169 - *out = module;
27.170 - return true;
27.171 -}
27.172 -
27.173 -bool
27.174 -PackageCache::import(Handle<Package> package, PathComponent *path, Importable **out)
27.175 -{
27.176 - // If the package is jailed, none of its imports are visible.
27.177 - if (package->jailed())
27.178 - return true;
27.179 -
27.180 - Local<Importable> obj(zone_, package->import(path->name));
27.181 - if (!obj) {
27.182 - // We couldn't find anything. Try the file system.
27.183 - if (!checkfs(package, path, out))
27.184 - return false;
27.185 -
27.186 - // checkfs will keep trying to import, so if it fails, we just
27.187 - // propagate up.
27.188 - return true;
27.189 - }
27.190 -
27.191 - // If we found an existing module, or the path has no next link, then
27.192 - // we can't go any further.
27.193 - if (obj->is(MapKind_Module) || !path->next) {
27.194 - *out = obj;
27.195 - return true;
27.196 - }
27.197 -
27.198 - Local<Package> subpackage(zone_, Package::cast(obj));
27.199 - return import(subpackage, path->next, out);
27.200 -}
27.201 -
27.202 -bool
27.203 -PackageCache::findOrAdd(Handle<Package> package, PathComponent *path, Importable **out)
27.204 -{
27.205 - // Local rooters should have initialized this, but whatever.
27.206 - assert(*out == NULL);
27.207 -
27.208 - // Try to import locally first.
27.209 - if (!import(package, path, out))
27.210 - return false;
27.211 - if (*out)
27.212 - return true;
27.213 -
27.214 - // Otherwise, search system roots.
27.215 - Local<Package> root(zone_);
27.216 - for (size_t i = 0; i < roots_.length(); i++) {
27.217 - root = roots_[i];
27.218 - if (!import(root, path, out))
27.219 - return false;
27.220 - if (*out)
27.221 - return true;
27.222 - }
27.223 -
27.224 - return true;
27.225 -}
27.226 -
27.227 -PackageCache::~PackageCache()
27.228 -{
27.229 -}
27.230 +/*
27.231 + * Copyright (C) 2012 David Anderson
27.232 + *
27.233 + * This file is part of SourcePawn.
27.234 + *
27.235 + * SourcePawn is free software: you can redistribute it and/or modify it under
27.236 + * the terms of the GNU General Public License as published by the Free
27.237 + * Software Foundation, either version 3 of the License, or (at your option)
27.238 + * any later version.
27.239 + *
27.240 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
27.241 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
27.242 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
27.243 + *
27.244 + * You should have received a copy of the GNU General Public License along with
27.245 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
27.246 + */
27.247 +#include <string.h>
27.248 +#include "Zone.h"
27.249 +#include "Heap.h"
27.250 +#include "Strings.h"
27.251 +#include "Modules.h"
27.252 +#include "Packages.h"
27.253 +#include "FileSystem.h"
27.254 +#include "List.h"
27.255 +#include "Heap-inl.h"
27.256 +#include "Handles-inl.h"
27.257 +
27.258 +using namespace ke;
27.259 +
27.260 +Package *
27.261 +Package::NewNormalized(Zone *zone, Handle<Package> parent, Handle<String> path, Handle<String> name, unsigned flags)
27.262 +{
27.263 + Local<Package> package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old)));
27.264 + if (!package)
27.265 + return NULL;
27.266 +
27.267 + // :TODO: assert path, name are atoms.
27.268 +
27.269 + package->flags_ = flags;
27.270 + package->name_ = name;
27.271 + package->parent_ = parent;
27.272 + package->path_ = path;
27.273 + package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL;
27.274 +
27.275 + return package;
27.276 +}
27.277 +
27.278 +Package *
27.279 +Package::New(Zone *zone, Handle<Package> parent, const char *path, Handle<String> name, unsigned flags)
27.280 +{
27.281 + Local<String> strpath(zone, zone->makeSymbol(path));
27.282 + if (!strpath)
27.283 + return NULL;
27.284 +
27.285 + return Package::NewNormalized(zone, parent, strpath, name, flags);
27.286 +}
27.287 +
27.288 +bool
27.289 +Package::add(Zone *zone, Handle<Importable> obj)
27.290 +{
27.291 + Local<Package> pkg(zone, this);
27.292 +
27.293 + assert(obj->parent() == pkg);
27.294 +
27.295 + if (!pkg->contents_) {
27.296 + pkg->contents_ = List<Importable>::New(zone);
27.297 + if (!pkg->contents_)
27.298 + return false;
27.299 + }
27.300 +
27.301 +#ifndef NDEBUG
27.302 + // Assert no duplicate names.
27.303 + for (unsigned i = 0; i < pkg->contents_->length(); i++)
27.304 + assert(pkg->contents_->at(i)->name() != obj->name());
27.305 +#endif
27.306 +
27.307 + if (!pkg->contents_->append(zone, obj))
27.308 + return false;
27.309 +
27.310 + return true;
27.311 +}
27.312 +
27.313 +Importable *
27.314 +Package::import(Handle<String> name)
27.315 +{
27.316 + if (!contents_)
27.317 + return NULL;
27.318 +
27.319 + for (unsigned i = 0; i < contents_->length(); i++) {
27.320 + Importable *obj = contents_->at(i);
27.321 + if (obj->isPackage() && Package::cast(obj)->name() == name)
27.322 + return obj;
27.323 + if (obj->isModule() && Module::cast(obj)->name() == name)
27.324 + return obj;
27.325 + }
27.326 +
27.327 + return NULL;
27.328 +}
27.329 +
27.330 +PackageCache::PackageCache(Zone *zone)
27.331 + : zone_(zone)
27.332 +{
27.333 +}
27.334 +
27.335 +bool
27.336 +PackageCache::initialize()
27.337 +{
27.338 + return true;
27.339 +}
27.340 +
27.341 +void
27.342 +PackageCache::accept(VirtualObjectVisitor *visitor)
27.343 +{
27.344 + for (size_t i = 0; i < roots_.length(); i++)
27.345 + visitor->visit(roots_[i].address());
27.346 +}
27.347 +
27.348 +bool
27.349 +PackageCache::checkfs(Handle<Package> package, PathComponent *path, Importable **out)
27.350 +{
27.351 + AutoFree<char> left(strdup(package->path()->chars()));
27.352 + AutoFree<char> right(strdup(path->name->chars()));
27.353 + AutoFree<char> result;
27.354 +
27.355 + if (!JoinPaths(zone_, result, *left, *right))
27.356 + return false;
27.357 +
27.358 + OS::PathType type = OS::InspectPath(*result);
27.359 + if (type == OS::Path_Folder) {
27.360 + // If there is a folder matching this path, create a new subpackage,
27.361 + // and then either return it (if this is the last link), or keep
27.362 + // trying to import the rest of the path.
27.363 + Local<String> strpath(zone_, zone_->makeSymbol(*result));
27.364 + Local<Package> subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal));
27.365 + if (!subpackage)
27.366 + return false;
27.367 + if (!path->next) {
27.368 + *out = subpackage;
27.369 + return true;
27.370 + }
27.371 + return import(subpackage, path->next, out);
27.372 + }
27.373 +
27.374 + // Otherwise, look for a file ending in ".sp".
27.375 + AutoFree<char> filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1));
27.376 + if (!*filepath)
27.377 + return false;
27.378 +
27.379 + strcpy(*filepath, *result);
27.380 + strcat(*filepath, ".sp");
27.381 +
27.382 + type = OS::InspectPath(*filepath);
27.383 + if (type != OS::Path_File)
27.384 + return true;
27.385 +
27.386 + // Create a new, empty module.
27.387 + Local<String> strpath(zone_, zone_->makeSymbol(*filepath));
27.388 + if (!strpath)
27.389 + return false;
27.390 +
27.391 + Local<Module> module(zone_, Module::New(zone_, package, strpath, path->name));
27.392 + if (!module || !package->add(zone_, module))
27.393 + return false;
27.394 +
27.395 + *out = module;
27.396 + return true;
27.397 +}
27.398 +
27.399 +bool
27.400 +PackageCache::import(Handle<Package> package, PathComponent *path, Importable **out)
27.401 +{
27.402 + // If the package is jailed, none of its imports are visible.
27.403 + if (package->jailed())
27.404 + return true;
27.405 +
27.406 + Local<Importable> obj(zone_, package->import(path->name));
27.407 + if (!obj) {
27.408 + // We couldn't find anything. Try the file system.
27.409 + if (!checkfs(package, path, out))
27.410 + return false;
27.411 +
27.412 + // checkfs will keep trying to import, so if it fails, we just
27.413 + // propagate up.
27.414 + return true;
27.415 + }
27.416 +
27.417 + // If we found an existing module, or the path has no next link, then
27.418 + // we can't go any further.
27.419 + if (obj->is(MapKind_Module) || !path->next) {
27.420 + *out = obj;
27.421 + return true;
27.422 + }
27.423 +
27.424 + Local<Package> subpackage(zone_, Package::cast(obj));
27.425 + return import(subpackage, path->next, out);
27.426 +}
27.427 +
27.428 +bool
27.429 +PackageCache::findOrAdd(Handle<Package> package, PathComponent *path, Importable **out)
27.430 +{
27.431 + // Local rooters should have initialized this, but whatever.
27.432 + assert(*out == NULL);
27.433 +
27.434 + // Try to import locally first.
27.435 + if (!import(package, path, out))
27.436 + return false;
27.437 + if (*out)
27.438 + return true;
27.439 +
27.440 + // Otherwise, search system roots.
27.441 + Local<Package> root(zone_);
27.442 + for (size_t i = 0; i < roots_.length(); i++) {
27.443 + root = roots_[i];
27.444 + if (!import(root, path, out))
27.445 + return false;
27.446 + if (*out)
27.447 + return true;
27.448 + }
27.449 +
27.450 + return true;
27.451 +}
27.452 +
27.453 +PackageCache::~PackageCache()
27.454 +{
27.455 +}
28.1 --- a/src/Packages.h Mon Jun 10 00:46:29 2013 +0100
28.2 +++ b/src/Packages.h Mon Jun 10 01:04:43 2013 +0100
28.3 @@ -1,193 +1,193 @@
28.4 -/*
28.5 - * Copyright (C) 2012 David Anderson
28.6 - *
28.7 - * This file is part of SourcePawn.
28.8 - *
28.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
28.10 - * the terms of the GNU General Public License as published by the Free
28.11 - * Software Foundation, either version 3 of the License, or (at your option)
28.12 - * any later version.
28.13 - *
28.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
28.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
28.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
28.17 - *
28.18 - * You should have received a copy of the GNU General Public License along with
28.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
28.20 - */
28.21 -#ifndef _include_sp2_packages_h_
28.22 -#define _include_sp2_packages_h_
28.23 -
28.24 -#include "PoolAllocator.h"
28.25 -#include "Objects.h"
28.26 -#include "HashTable.h"
28.27 -
28.28 -namespace ke {
28.29 -
28.30 -class String;
28.31 -class Module;
28.32 -class Package;
28.33 -class ImportStatement;
28.34 -class VirtualObjectVisitor;
28.35 -
28.36 -template <typename T> class List;
28.37 -
28.38 -struct PathComponent : PoolObject
28.39 -{
28.40 - PathComponent(ScopedRoot<String> *name, PathComponent *next)
28.41 - : name(*name),
28.42 - next(next)
28.43 - {
28.44 - }
28.45 - ScopedRoot<String> &name;
28.46 - PathComponent *next;
28.47 -};
28.48 -
28.49 -class Importable : public Object
28.50 -{
28.51 - public:
28.52 - Package *parent() {
28.53 - return parent_;
28.54 - }
28.55 - String *path() {
28.56 - return path_;
28.57 - }
28.58 - String *name() {
28.59 - return name_;
28.60 - }
28.61 -
28.62 - bool isModule() {
28.63 - return is(MapKind_Module);
28.64 - }
28.65 - bool isPackage() {
28.66 - return is(MapKind_Package);
28.67 - }
28.68 -
28.69 - static inline size_t offsetOfName() {
28.70 - return OFFSETOF(Importable, name_);
28.71 - }
28.72 - static inline size_t offsetOfParent() {
28.73 - return OFFSETOF(Importable, parent_);
28.74 - }
28.75 - static inline size_t offsetOfPath() {
28.76 - return OFFSETOF(Importable, path_);
28.77 - }
28.78 -
28.79 - static inline Importable *cast(Object *obj) {
28.80 - assert(!obj || obj->is(MapKind_Module) || obj->is(MapKind_Package));
28.81 - return reinterpret_cast<Importable *>(obj);
28.82 - }
28.83 -
28.84 - protected:
28.85 - Barriered<String> name_;
28.86 - Barriered<Package> parent_;
28.87 - Barriered<String> path_;
28.88 -};
28.89 -
28.90 -// A package is a single folder in the file system, and contains any number of
28.91 -// modules and sub-packages. The package hierarchy forms a tree. For simplicity
28.92 -// the root of the tree is an anonymous package that contains no modules.
28.93 -//
28.94 -// Each package in the package hierarchy has two components of path information:
28.95 -// (1) Canonical path. This is a normalized path used to compute the paths of
28.96 -// modules.
28.97 -// (2) Name. This is the package's name as it would appear in a path
28.98 -// component. It is optional.
28.99 -//
28.100 -// Packages may be "hidden", meaning that even if they have names, their name
28.101 -// is not accessible from any import statements. Packages may also be "jailed",
28.102 -// meaning that other names in the package are not visible to each other.
28.103 -//
28.104 -// Packages are created in a few ways:
28.105 -//
28.106 -// (1) System Roots. A system root is a default search location for imports,
28.107 -// and they are installed at the top-level of the hierarchy by the host
28.108 -// application. A system root has a unique top-level name and path.
28.109 -// System roots are always hidden.
28.110 -//
28.111 -// (2) Imports. When importing, the package hierarchy may be extended as
28.112 -// new paths are discovered. Packages discovered this way are never
28.113 -// hidden or jailed.
28.114 -//
28.115 -// (3) Via Package::New(), which creates an empty package. This can be used
28.116 -// to create custom packages.
28.117 -class Package : public Importable
28.118 -{
28.119 - public:
28.120 - enum {
28.121 - Normal = 0,
28.122 -
28.123 - // These must match the flags in the public API for Package.
28.124 - Hidden = (1 << 0),
28.125 - Jailed = (1 << 1)
28.126 - };
28.127 -
28.128 - public:
28.129 - static Package *NewNormalized(Zone *zone,
28.130 - Handle<Package> parent,
28.131 - Handle<String> path,
28.132 - Handle<String> name,
28.133 - unsigned flags);
28.134 - static Package *New(Zone *zone,
28.135 - Handle<Package> parent,
28.136 - const char *path,
28.137 - Handle<String> name,
28.138 - unsigned flags);
28.139 -
28.140 - bool add(Zone *zone, Handle<Importable> component);
28.141 -
28.142 - bool hidden() {
28.143 - return !!(flags_ & Package::Hidden);
28.144 - }
28.145 - bool jailed() {
28.146 - return !!(flags_ & Package::Jailed);
28.147 - }
28.148 -
28.149 - void setNativeIdentity(void *identity) {
28.150 - nativeIdentity_ = identity;
28.151 - }
28.152 - void *getNativeIdentity() {
28.153 - return nativeIdentity_;
28.154 - }
28.155 - Importable *import(Handle<String> name);
28.156 -
28.157 - // Begin GC descriptor.
28.158 - static inline size_t offsetOfContents() {
28.159 - return OFFSETOF(Package, contents_);
28.160 - }
28.161 - // End GC descriptor.
28.162 -
28.163 - static inline Package *cast(Object *obj) {
28.164 - assert(!obj || obj->is(MapKind_Package));
28.165 - return reinterpret_cast<Package *>(obj);
28.166 - }
28.167 -
28.168 - private:
28.169 - unsigned flags_;
28.170 - Barriered<List<Importable> > contents_;
28.171 - void *nativeIdentity_;
28.172 -};
28.173 -
28.174 -class PackageCache
28.175 -{
28.176 - public:
28.177 - PackageCache(Zone *zone);
28.178 - ~PackageCache();
28.179 - bool initialize();
28.180 -
28.181 - bool findOrAdd(Handle<Package> package, PathComponent *path, Importable **out);
28.182 -
28.183 - void accept(VirtualObjectVisitor *visitor);
28.184 -
28.185 - private:
28.186 - bool import(Handle<Package> package, PathComponent *path, Importable **out);
28.187 - bool checkfs(Handle<Package> package, PathComponent *path, Importable **out);
28.188 -
28.189 - private:
28.190 - Zone *zone_;
28.191 - Vector<Unbarriered<Package> > roots_;
28.192 -};
28.193 -
28.194 -} // namespace ke
28.195 -
28.196 -#endif // _include_sp2_packages_h_
28.197 +/*
28.198 + * Copyright (C) 2012 David Anderson
28.199 + *
28.200 + * This file is part of SourcePawn.
28.201 + *
28.202 + * SourcePawn is free software: you can redistribute it and/or modify it under
28.203 + * the terms of the GNU General Public License as published by the Free
28.204 + * Software Foundation, either version 3 of the License, or (at your option)
28.205 + * any later version.
28.206 + *
28.207 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
28.208 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
28.209 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
28.210 + *
28.211 + * You should have received a copy of the GNU General Public License along with
28.212 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
28.213 + */
28.214 +#ifndef _include_sp2_packages_h_
28.215 +#define _include_sp2_packages_h_
28.216 +
28.217 +#include "PoolAllocator.h"
28.218 +#include "Objects.h"
28.219 +#include "HashTable.h"
28.220 +
28.221 +namespace ke {
28.222 +
28.223 +class String;
28.224 +class Module;
28.225 +class Package;
28.226 +class ImportStatement;
28.227 +class VirtualObjectVisitor;
28.228 +
28.229 +template <typename T> class List;
28.230 +
28.231 +struct PathComponent : PoolObject
28.232 +{
28.233 + PathComponent(ScopedRoot<String> *name, PathComponent *next)
28.234 + : name(*name),
28.235 + next(next)
28.236 + {
28.237 + }
28.238 + ScopedRoot<String> &name;
28.239 + PathComponent *next;
28.240 +};
28.241 +
28.242 +class Importable : public Object
28.243 +{
28.244 + public:
28.245 + Package *parent() {
28.246 + return parent_;
28.247 + }
28.248 + String *path() {
28.249 + return path_;
28.250 + }
28.251 + String *name() {
28.252 + return name_;
28.253 + }
28.254 +
28.255 + bool isModule() {
28.256 + return is(MapKind_Module);
28.257 + }
28.258 + bool isPackage() {
28.259 + return is(MapKind_Package);
28.260 + }
28.261 +
28.262 + static inline size_t offsetOfName() {
28.263 + return OFFSETOF(Importable, name_);
28.264 + }
28.265 + static inline size_t offsetOfParent() {
28.266 + return OFFSETOF(Importable, parent_);
28.267 + }
28.268 + static inline size_t offsetOfPath() {
28.269 + return OFFSETOF(Importable, path_);
28.270 + }
28.271 +
28.272 + static inline Importable *cast(Object *obj) {
28.273 + assert(!obj || obj->is(MapKind_Module) || obj->is(MapKind_Package));
28.274 + return reinterpret_cast<Importable *>(obj);
28.275 + }
28.276 +
28.277 + protected:
28.278 + Barriered<String> name_;
28.279 + Barriered<Package> parent_;
28.280 + Barriered<String> path_;
28.281 +};
28.282 +
28.283 +// A package is a single folder in the file system, and contains any number of
28.284 +// modules and sub-packages. The package hierarchy forms a tree. For simplicity
28.285 +// the root of the tree is an anonymous package that contains no modules.
28.286 +//
28.287 +// Each package in the package hierarchy has two components of path information:
28.288 +// (1) Canonical path. This is a normalized path used to compute the paths of
28.289 +// modules.
28.290 +// (2) Name. This is the package's name as it would appear in a path
28.291 +// component. It is optional.
28.292 +//
28.293 +// Packages may be "hidden", meaning that even if they have names, their name
28.294 +// is not accessible from any import statements. Packages may also be "jailed",
28.295 +// meaning that other names in the package are not visible to each other.
28.296 +//
28.297 +// Packages are created in a few ways:
28.298 +//
28.299 +// (1) System Roots. A system root is a default search location for imports,
28.300 +// and they are installed at the top-level of the hierarchy by the host
28.301 +// application. A system root has a unique top-level name and path.
28.302 +// System roots are always hidden.
28.303 +//
28.304 +// (2) Imports. When importing, the package hierarchy may be extended as
28.305 +// new paths are discovered. Packages discovered this way are never
28.306 +// hidden or jailed.
28.307 +//
28.308 +// (3) Via Package::New(), which creates an empty package. This can be used
28.309 +// to create custom packages.
28.310 +class Package : public Importable
28.311 +{
28.312 + public:
28.313 + enum {
28.314 + Normal = 0,
28.315 +
28.316 + // These must match the flags in the public API for Package.
28.317 + Hidden = (1 << 0),
28.318 + Jailed = (1 << 1)
28.319 + };
28.320 +
28.321 + public:
28.322 + static Package *NewNormalized(Zone *zone,
28.323 + Handle<Package> parent,
28.324 + Handle<String> path,
28.325 + Handle<String> name,
28.326 + unsigned flags);
28.327 + static Package *New(Zone *zone,
28.328 + Handle<Package> parent,
28.329 + const char *path,
28.330 + Handle<String> name,
28.331 + unsigned flags);
28.332 +
28.333 + bool add(Zone *zone, Handle<Importable> component);
28.334 +
28.335 + bool hidden() {
28.336 + return !!(flags_ & Package::Hidden);
28.337 + }
28.338 + bool jailed() {
28.339 + return !!(flags_ & Package::Jailed);
28.340 + }
28.341 +
28.342 + void setNativeIdentity(void *identity) {
28.343 + nativeIdentity_ = identity;
28.344 + }
28.345 + void *getNativeIdentity() {
28.346 + return nativeIdentity_;
28.347 + }
28.348 + Importable *import(Handle<String> name);
28.349 +
28.350 + // Begin GC descriptor.
28.351 + static inline size_t offsetOfContents() {
28.352 + return OFFSETOF(Package, contents_);
28.353 + }
28.354 + // End GC descriptor.
28.355 +
28.356 + static inline Package *cast(Object *obj) {
28.357 + assert(!obj || obj->is(MapKind_Package));
28.358 + return reinterpret_cast<Package *>(obj);
28.359 + }
28.360 +
28.361 + private:
28.362 + unsigned flags_;
28.363 + Barriered<List<Importable> > contents_;
28.364 + void *nativeIdentity_;
28.365 +};
28.366 +
28.367 +class PackageCache
28.368 +{
28.369 + public:
28.370 + PackageCache(Zone *zone);
28.371 + ~PackageCache();
28.372 + bool initialize();
28.373 +
28.374 + bool findOrAdd(Handle<Package> package, PathComponent *path, Importable **out);
28.375 +
28.376 + void accept(VirtualObjectVisitor *visitor);
28.377 +
28.378 + private:
28.379 + bool import(Handle<Package> package, PathComponent *path, Importable **out);
28.380 + bool checkfs(Handle<Package> package, PathComponent *path, Importable **out);
28.381 +
28.382 + private:
28.383 + Zone *zone_;
28.384 + Vector<Unbarriered<Package> > roots_;
28.385 +};
28.386 +
28.387 +} // namespace ke
28.388 +
28.389 +#endif // _include_sp2_packages_h_
29.1 --- a/src/PoolAllocator.cpp Mon Jun 10 00:46:29 2013 +0100
29.2 +++ b/src/PoolAllocator.cpp Mon Jun 10 01:04:43 2013 +0100
29.3 @@ -1,131 +1,131 @@
29.4 -/*
29.5 - * Copyright (C) 2012 David Anderson
29.6 - *
29.7 - * This file is part of JITCraft.
29.8 - *
29.9 - * JITCraft is free software: you can redistribute it and/or modify it under
29.10 - * the terms of the GNU General Public License as published by the Free
29.11 - * Software Foundation, either version 3 of the License, or (at your option)
29.12 - * any later version.
29.13 - *
29.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
29.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
29.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
29.17 - *
29.18 - * You should have received a copy of the GNU General Public License along with
29.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
29.20 - */
29.21 -#include <assert.h>
29.22 -#include <stdlib.h>
29.23 -#include <new>
29.24 -#include "PoolAllocator.h"
29.25 -#include "Zone.h"
29.26 -#include "Spaces-inl.h"
29.27 -#include "Heap-inl.h"
29.28 -
29.29 -using namespace ke;
29.30 -
29.31 -PoolAllocator::PoolAllocator()
29.32 - : reserved_(NULL),
29.33 - last_(NULL)
29.34 -{
29.35 -}
29.36 -
29.37 -PoolAllocator::~PoolAllocator()
29.38 -{
29.39 - unwind(NULL);
29.40 - if (reserved_)
29.41 - free(reserved_);
29.42 -}
29.43 -
29.44 -char *
29.45 -PoolAllocator::enter()
29.46 -{
29.47 - if (!last_)
29.48 - return NULL;
29.49 - return last_->ptr;
29.50 -}
29.51 -
29.52 -void
29.53 -PoolAllocator::leave(char *pos)
29.54 -{
29.55 - unwind(pos);
29.56 -}
29.57 -
29.58 -void
29.59 -PoolAllocator::unwind(char *pos)
29.60 -{
29.61 - while (last_) {
29.62 - if (pos && pos >= last_->base && pos < last_->end)
29.63 - break;
29.64 - Pool *prev = last_->prev;
29.65 - {
29.66 - if (last_->size() <= kMaxReserveSize &&
29.67 - (!reserved_ || reserved_->size() < last_->size()))
29.68 - {
29.69 - if (reserved_)
29.70 - free(reserved_);
29.71 - reserved_ = last_;
29.72 - } else {
29.73 - free(last_);
29.74 - }
29.75 - }
29.76 - last_ = prev;
29.77 - }
29.78 -
29.79 - if (!last_) {
29.80 - assert(!pos);
29.81 - return;
29.82 - }
29.83 -
29.84 - last_->ptr = pos;
29.85 -}
29.86 -
29.87 -void *
29.88 -PoolAllocator::slowAllocate(size_t actualBytes)
29.89 -{
29.90 - size_t bytesNeeded = actualBytes + sizeof(Pool);
29.91 - if (bytesNeeded < kDefaultPoolSize)
29.92 - bytesNeeded = kDefaultPoolSize;
29.93 -
29.94 - Pool *pool;
29.95 - if (reserved_ && reserved_->size() >= bytesNeeded) {
29.96 - pool = reserved_;
29.97 - reserved_ = NULL;
29.98 - } else {
29.99 - pool = (Pool *)malloc(bytesNeeded);
29.100 - if (!pool) {
29.101 - ZONE()->reportOutOfMemory();
29.102 - return NULL;
29.103 - }
29.104 - pool->base = (char *)(pool + 1);
29.105 - pool->end = (char *)pool + bytesNeeded;
29.106 - }
29.107 - pool->ptr = pool->base + actualBytes;
29.108 - pool->prev = last_;
29.109 - last_ = pool;
29.110 - return pool->base;
29.111 -}
29.112 -
29.113 -void
29.114 -PoolAllocationPolicy::reportOutOfMemory()
29.115 -{
29.116 - ZONE()->reportOutOfMemory();
29.117 -}
29.118 -
29.119 -void
29.120 -PoolAllocationPolicy::reportAllocationOverflow()
29.121 -{
29.122 - ZONE()->reportError(Message_AllocationOverflow);
29.123 -}
29.124 -
29.125 -void *
29.126 -PoolAllocationPolicy::malloc(size_t bytes)
29.127 -{
29.128 - return ZONE()->pool().rawAllocate(bytes);
29.129 -}
29.130 -
29.131 -void
29.132 -PoolAllocationPolicy::free(void *ptr)
29.133 -{
29.134 -}
29.135 +/*
29.136 + * Copyright (C) 2012 David Anderson
29.137 + *
29.138 + * This file is part of JITCraft.
29.139 + *
29.140 + * JITCraft is free software: you can redistribute it and/or modify it under
29.141 + * the terms of the GNU General Public License as published by the Free
29.142 + * Software Foundation, either version 3 of the License, or (at your option)
29.143 + * any later version.
29.144 + *
29.145 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
29.146 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
29.147 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
29.148 + *
29.149 + * You should have received a copy of the GNU General Public License along with
29.150 + * JITCraft. If not, see http://www.gnu.org/licenses/.
29.151 + */
29.152 +#include <assert.h>
29.153 +#include <stdlib.h>
29.154 +#include <new>
29.155 +#include "PoolAllocator.h"
29.156 +#include "Zone.h"
29.157 +#include "Spaces-inl.h"
29.158 +#include "Heap-inl.h"
29.159 +
29.160 +using namespace ke;
29.161 +
29.162 +PoolAllocator::PoolAllocator()
29.163 + : reserved_(NULL),
29.164 + last_(NULL)
29.165 +{
29.166 +}
29.167 +
29.168 +PoolAllocator::~PoolAllocator()
29.169 +{
29.170 + unwind(NULL);
29.171 + if (reserved_)
29.172 + free(reserved_);
29.173 +}
29.174 +
29.175 +char *
29.176 +PoolAllocator::enter()
29.177 +{
29.178 + if (!last_)
29.179 + return NULL;
29.180 + return last_->ptr;
29.181 +}
29.182 +
29.183 +void
29.184 +PoolAllocator::leave(char *pos)
29.185 +{
29.186 + unwind(pos);
29.187 +}
29.188 +
29.189 +void
29.190 +PoolAllocator::unwind(char *pos)
29.191 +{
29.192 + while (last_) {
29.193 + if (pos && pos >= last_->base && pos < last_->end)
29.194 + break;
29.195 + Pool *prev = last_->prev;
29.196 + {
29.197 + if (last_->size() <= kMaxReserveSize &&
29.198 + (!reserved_ || reserved_->size() < last_->size()))
29.199 + {
29.200 + if (reserved_)
29.201 + free(reserved_);
29.202 + reserved_ = last_;
29.203 + } else {
29.204 + free(last_);
29.205 + }
29.206 + }
29.207 + last_ = prev;
29.208 + }
29.209 +
29.210 + if (!last_) {
29.211 + assert(!pos);
29.212 + return;
29.213 + }
29.214 +
29.215 + last_->ptr = pos;
29.216 +}
29.217 +
29.218 +void *
29.219 +PoolAllocator::slowAllocate(size_t actualBytes)
29.220 +{
29.221 + size_t bytesNeeded = actualBytes + sizeof(Pool);
29.222 + if (bytesNeeded < kDefaultPoolSize)
29.223 + bytesNeeded = kDefaultPoolSize;
29.224 +
29.225 + Pool *pool;
29.226 + if (reserved_ && reserved_->size() >= bytesNeeded) {
29.227 + pool = reserved_;
29.228 + reserved_ = NULL;
29.229 + } else {
29.230 + pool = (Pool *)malloc(bytesNeeded);
29.231 + if (!pool) {
29.232 + ZONE()->reportOutOfMemory();
29.233 + return NULL;
29.234 + }
29.235 + pool->base = (char *)(pool + 1);
29.236 + pool->end = (char *)pool + bytesNeeded;
29.237 + }
29.238 + pool->ptr = pool->base + actualBytes;
29.239 + pool->prev = last_;
29.240 + last_ = pool;
29.241 + return pool->base;
29.242 +}
29.243 +
29.244 +void
29.245 +PoolAllocationPolicy::reportOutOfMemory()
29.246 +{
29.247 + ZONE()->reportOutOfMemory();
29.248 +}
29.249 +
29.250 +void
29.251 +PoolAllocationPolicy::reportAllocationOverflow()
29.252 +{
29.253 + ZONE()->reportError(Message_AllocationOverflow);
29.254 +}
29.255 +
29.256 +void *
29.257 +PoolAllocationPolicy::malloc(size_t bytes)
29.258 +{
29.259 + return ZONE()->pool().rawAllocate(bytes);
29.260 +}
29.261 +
29.262 +void
29.263 +PoolAllocationPolicy::free(void *ptr)
29.264 +{
29.265 +}
30.1 --- a/src/PoolAllocator.h Mon Jun 10 00:46:29 2013 +0100
30.2 +++ b/src/PoolAllocator.h Mon Jun 10 01:04:43 2013 +0100
30.3 @@ -1,145 +1,145 @@
30.4 -/*
30.5 - * Copyright (C) 2012 David Anderson
30.6 - *
30.7 - * This file is part of JITCraft.
30.8 - *
30.9 - * JITCraft is free software: you can redistribute it and/or modify it under
30.10 - * the terms of the GNU General Public License as published by the Free
30.11 - * Software Foundation, either version 3 of the License, or (at your option)
30.12 - * any later version.
30.13 - *
30.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
30.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
30.17 - *
30.18 - * You should have received a copy of the GNU General Public License along with
30.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
30.20 - */
30.21 -#ifndef _include_jitcraft_pool_allocator_h_
30.22 -#define _include_jitcraft_pool_allocator_h_
30.23 -
30.24 -#include <new>
30.25 -#include <stddef.h>
30.26 -#include <limits.h>
30.27 -#include "Utility.h"
30.28 -#include "Vector.h"
30.29 -
30.30 -namespace ke {
30.31 -
30.32 -// Allocates memory in chunks that are not freed until the entire allocator
30.33 -// is freed. This is intended for use with large, temporary data structures.
30.34 -class PoolAllocator
30.35 -{
30.36 - friend class PoolAllocationScope;
30.37 -
30.38 - struct Pool {
30.39 - char *base;
30.40 - char *ptr;
30.41 - char *end;
30.42 - Pool *prev;
30.43 -
30.44 - size_t size() const {
30.45 - return size_t(end - base);
30.46 - }
30.47 - };
30.48 -
30.49 - static const size_t kDefaultPoolSize = 8 * 1024;
30.50 - static const size_t kMaxReserveSize = 64 * 1024;
30.51 -
30.52 - private:
30.53 - Pool *reserved_;
30.54 - Pool *last_;
30.55 -
30.56 - private:
30.57 - void unwind(char *pos);
30.58 - void *slowAllocate(size_t actualBytes);
30.59 -
30.60 - public:
30.61 - PoolAllocator();
30.62 - ~PoolAllocator();
30.63 -
30.64 - void *rawAllocate(size_t bytes) {
30.65 - // Guarantee malloc alignment.
30.66 - size_t actualBytes = Align(bytes, kMallocAlignment);
30.67 - if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
30.68 - return slowAllocate(actualBytes);
30.69 - char *ptr = last_->ptr;
30.70 - last_->ptr += actualBytes;
30.71 - return ptr;
30.72 - }
30.73 -
30.74 - template <typename T>
30.75 - T *alloc(size_t count = 1) {
30.76 - void *ptr = rawAllocate(count * sizeof(T));
30.77 - if (!ptr)
30.78 - return NULL;
30.79 -
30.80 - return reinterpret_cast<T *>(ptr);
30.81 - }
30.82 -
30.83 - char *enter();
30.84 - void leave(char *position);
30.85 -};
30.86 -
30.87 -class PoolScope
30.88 -{
30.89 - PoolAllocator &pool_;
30.90 - char *position_;
30.91 -
30.92 - public:
30.93 - PoolScope(PoolAllocator &allocator)
30.94 - : pool_(allocator),
30.95 - position_(allocator.enter())
30.96 - {
30.97 - }
30.98 - ~PoolScope()
30.99 - {
30.100 - pool_.leave(position_);
30.101 - }
30.102 -};
30.103 -
30.104 -class PoolObject
30.105 -{
30.106 - public:
30.107 - void *operator new(size_t size, PoolAllocator &pool) {
30.108 - return pool.rawAllocate(size);
30.109 - }
30.110 - void *operator new [](size_t size, PoolAllocator &pool) {
30.111 - return pool.rawAllocate(size);
30.112 - }
30.113 -
30.114 - // Using delete on pool-allocated objects is illegal.
30.115 - void operator delete(void *ptr, PoolAllocator &pool) {
30.116 - assert(false);
30.117 - }
30.118 - void operator delete [](void *ptr, PoolAllocator &pool) {
30.119 - assert(false);
30.120 - }
30.121 -};
30.122 -
30.123 -class PoolAllocationPolicy
30.124 -{
30.125 - protected:
30.126 - void reportAllocationOverflow();
30.127 - void reportOutOfMemory();
30.128 -
30.129 - public:
30.130 - void *malloc(size_t bytes);
30.131 - void free(void *ptr);
30.132 -};
30.133 -
30.134 -template <typename T>
30.135 -class PoolList
30.136 - : public Vector<T, PoolAllocationPolicy>,
30.137 - public PoolObject
30.138 -{
30.139 - public:
30.140 - PoolList()
30.141 - : Vector<T, PoolAllocationPolicy>(PoolAllocationPolicy())
30.142 - {
30.143 - }
30.144 -};
30.145 -
30.146 -}
30.147 -
30.148 -#endif // _include_jitcraft_pool_allocator_h_
30.149 +/*
30.150 + * Copyright (C) 2012 David Anderson
30.151 + *
30.152 + * This file is part of JITCraft.
30.153 + *
30.154 + * JITCraft is free software: you can redistribute it and/or modify it under
30.155 + * the terms of the GNU General Public License as published by the Free
30.156 + * Software Foundation, either version 3 of the License, or (at your option)
30.157 + * any later version.
30.158 + *
30.159 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
30.160 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30.161 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
30.162 + *
30.163 + * You should have received a copy of the GNU General Public License along with
30.164 + * JITCraft. If not, see http://www.gnu.org/licenses/.
30.165 + */
30.166 +#ifndef _include_jitcraft_pool_allocator_h_
30.167 +#define _include_jitcraft_pool_allocator_h_
30.168 +
30.169 +#include <new>
30.170 +#include <stddef.h>
30.171 +#include <limits.h>
30.172 +#include "Utility.h"
30.173 +#include "Vector.h"
30.174 +
30.175 +namespace ke {
30.176 +
30.177 +// Allocates memory in chunks that are not freed until the entire allocator
30.178 +// is freed. This is intended for use with large, temporary data structures.
30.179 +class PoolAllocator
30.180 +{
30.181 + friend class PoolAllocationScope;
30.182 +
30.183 + struct Pool {
30.184 + char *base;
30.185 + char *ptr;
30.186 + char *end;
30.187 + Pool *prev;
30.188 +
30.189 + size_t size() const {
30.190 + return size_t(end - base);
30.191 + }
30.192 + };
30.193 +
30.194 + static const size_t kDefaultPoolSize = 8 * 1024;
30.195 + static const size_t kMaxReserveSize = 64 * 1024;
30.196 +
30.197 + private:
30.198 + Pool *reserved_;
30.199 + Pool *last_;
30.200 +
30.201 + private:
30.202 + void unwind(char *pos);
30.203 + void *slowAllocate(size_t actualBytes);
30.204 +
30.205 + public:
30.206 + PoolAllocator();
30.207 + ~PoolAllocator();
30.208 +
30.209 + void *rawAllocate(size_t bytes) {
30.210 + // Guarantee malloc alignment.
30.211 + size_t actualBytes = Align(bytes, kMallocAlignment);
30.212 + if (!last_ || (size_t(last_->end - last_->ptr) < actualBytes))
30.213 + return slowAllocate(actualBytes);
30.214 + char *ptr = last_->ptr;
30.215 + last_->ptr += actualBytes;
30.216 + return ptr;
30.217 + }
30.218 +
30.219 + template <typename T>
30.220 + T *alloc(size_t count = 1) {
30.221 + void *ptr = rawAllocate(count * sizeof(T));
30.222 + if (!ptr)
30.223 + return NULL;
30.224 +
30.225 + return reinterpret_cast<T *>(ptr);
30.226 + }
30.227 +
30.228 + char *enter();
30.229 + void leave(char *position);
30.230 +};
30.231 +
30.232 +class PoolScope
30.233 +{
30.234 + PoolAllocator &pool_;
30.235 + char *position_;
30.236 +
30.237 + public:
30.238 + PoolScope(PoolAllocator &allocator)
30.239 + : pool_(allocator),
30.240 + position_(allocator.enter())
30.241 + {
30.242 + }
30.243 + ~PoolScope()
30.244 + {
30.245 + pool_.leave(position_);
30.246 + }
30.247 +};
30.248 +
30.249 +class PoolObject
30.250 +{
30.251 + public:
30.252 + void *operator new(size_t size, PoolAllocator &pool) {
30.253 + return pool.rawAllocate(size);
30.254 + }
30.255 + void *operator new [](size_t size, PoolAllocator &pool) {
30.256 + return pool.rawAllocate(size);
30.257 + }
30.258 +
30.259 + // Using delete on pool-allocated objects is illegal.
30.260 + void operator delete(void *ptr, PoolAllocator &pool) {
30.261 + assert(false);
30.262 + }
30.263 + void operator delete [](void *ptr, PoolAllocator &pool) {
30.264 + assert(false);
30.265 + }
30.266 +};
30.267 +
30.268 +class PoolAllocationPolicy
30.269 +{
30.270 + protected:
30.271 + void reportAllocationOverflow();
30.272 + void reportOutOfMemory();
30.273 +
30.274 + public:
30.275 + void *malloc(size_t bytes);
30.276 + void free(void *ptr);
30.277 +};
30.278 +
30.279 +template <typename T>
30.280 +class PoolList
30.281 + : public Vector<T, PoolAllocationPolicy>,
30.282 + public PoolObject
30.283 +{
30.284 + public:
30.285 + PoolList()
30.286 + : Vector<T, PoolAllocationPolicy>(PoolAllocationPolicy())
30.287 + {
30.288 + }
30.289 +};
30.290 +
30.291 +}
30.292 +
30.293 +#endif // _include_jitcraft_pool_allocator_h_
31.1 --- a/src/Reference.cpp Mon Jun 10 00:46:29 2013 +0100
31.2 +++ b/src/Reference.cpp Mon Jun 10 01:04:43 2013 +0100
31.3 @@ -1,51 +1,51 @@
31.4 -/* vim: set ts=4 sw=4 tw=99 et:
31.5 - *
31.6 - * Copyright (C) 2012 David Anderson
31.7 - *
31.8 - * This file is part of SourcePawn.
31.9 - *
31.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
31.11 - * the terms of the GNU General Public License as published by the Free
31.12 - * Software Foundation, either version 3 of the License, or (at your option)
31.13 - * any later version.
31.14 - *
31.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
31.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
31.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31.18 - *
31.19 - * You should have received a copy of the GNU General Public License along with
31.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
31.21 - */
31.22 -#include "Reference.h"
31.23 -#include "Zone.h"
31.24 -#include "Array.h"
31.25 -#include "Structures.h"
31.26 -#include "Heap-inl.h"
31.27 -
31.28 -using namespace ke;
31.29 -
31.30 -Reference *
31.31 -Reference::NewStack(Zone *zone, void *location, Heap::Tenure tenure)
31.32 -{
31.33 - Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
31.34 - if (!ref)
31.35 - return NULL;
31.36 -
31.37 - ref->location_ = location;
31.38 - ref->base_ = NULL;
31.39 - return ref;
31.40 -}
31.41 -
31.42 -Reference *
31.43 -Reference::NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure)
31.44 -{
31.45 - Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
31.46 - if (!ref)
31.47 - return NULL;
31.48 -
31.49 - ref->location_ = &ref->slot_;
31.50 - ref->slot_ = slot;
31.51 - ref->base_ = NULL;
31.52 - return ref;
31.53 -}
31.54 -
31.55 +/* vim: set ts=4 sw=4 tw=99 et:
31.56 + *
31.57 + * Copyright (C) 2012 David Anderson
31.58 + *
31.59 + * This file is part of SourcePawn.
31.60 + *
31.61 + * SourcePawn is free software: you can redistribute it and/or modify it under
31.62 + * the terms of the GNU General Public License as published by the Free
31.63 + * Software Foundation, either version 3 of the License, or (at your option)
31.64 + * any later version.
31.65 + *
31.66 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
31.67 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
31.68 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31.69 + *
31.70 + * You should have received a copy of the GNU General Public License along with
31.71 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
31.72 + */
31.73 +#include "Reference.h"
31.74 +#include "Zone.h"
31.75 +#include "Array.h"
31.76 +#include "Structures.h"
31.77 +#include "Heap-inl.h"
31.78 +
31.79 +using namespace ke;
31.80 +
31.81 +Reference *
31.82 +Reference::NewStack(Zone *zone, void *location, Heap::Tenure tenure)
31.83 +{
31.84 + Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
31.85 + if (!ref)
31.86 + return NULL;
31.87 +
31.88 + ref->location_ = location;
31.89 + ref->base_ = NULL;
31.90 + return ref;
31.91 +}
31.92 +
31.93 +Reference *
31.94 +Reference::NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure)
31.95 +{
31.96 + Local<Reference> ref(zone, Reference::cast(zone->allocate(MapKind_Reference, sizeof(Reference), tenure)));
31.97 + if (!ref)
31.98 + return NULL;
31.99 +
31.100 + ref->location_ = &ref->slot_;
31.101 + ref->slot_ = slot;
31.102 + ref->base_ = NULL;
31.103 + return ref;
31.104 +}
31.105 +
32.1 --- a/src/Reference.h Mon Jun 10 00:46:29 2013 +0100
32.2 +++ b/src/Reference.h Mon Jun 10 01:04:43 2013 +0100
32.3 @@ -1,76 +1,76 @@
32.4 -/*
32.5 - * Copyright (C) 2012 David Anderson
32.6 - *
32.7 - * This file is part of SourcePawn.
32.8 - *
32.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
32.10 - * the terms of the GNU General Public License as published by the Free
32.11 - * Software Foundation, either version 3 of the License, or (at your option)
32.12 - * any later version.
32.13 - *
32.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
32.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
32.17 - *
32.18 - * You should have received a copy of the GNU General Public License along with
32.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
32.20 - */
32.21 -#ifndef _include_jitcraft_reference_h_
32.22 -#define _include_jitcraft_reference_h_
32.23 -
32.24 -#include "Heap.h"
32.25 -#include "Barriers.h"
32.26 -#include "Stack.h"
32.27 -
32.28 -namespace ke {
32.29 -
32.30 -class Array;
32.31 -class Struct;
32.32 -
32.33 -// A Reference is a typed pointer to another location in memory.
32.34 -class Reference : public Object
32.35 -{
32.36 - void *location_;
32.37 - Barriered<Object> base_;
32.38 -
32.39 - // We do not compute references to objects, so this does not need to be
32.40 - // traced.
32.41 - LocalSlot slot_;
32.42 -
32.43 - public:
32.44 - static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
32.45 - static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
32.46 -
32.47 - int getInt() {
32.48 - return *reinterpret_cast<int *>(location_);
32.49 - }
32.50 - void setInt(int i) {
32.51 - *reinterpret_cast<int *>(location_) = i;
32.52 - }
32.53 - float getFloat() {
32.54 - return *reinterpret_cast<float *>(location_);
32.55 - }
32.56 - void setFloat(float f) {
32.57 - *reinterpret_cast<float *>(location_) = f;
32.58 - }
32.59 -
32.60 - // WARNING! This should only be for Native calls.
32.61 - void *location() {
32.62 - return location_;
32.63 - }
32.64 -
32.65 - // Begin GC Descriptor.
32.66 - static inline size_t offsetOfBase() {
32.67 - return offsetof(Reference, base_);
32.68 - }
32.69 - // End GC Descriptor.
32.70 -
32.71 - static inline Reference *cast(Object *obj) {
32.72 - assert(!obj || obj->is(MapKind_Reference));
32.73 - return reinterpret_cast<Reference *>(obj);
32.74 - }
32.75 -};
32.76 -
32.77 -}
32.78 -
32.79 -#endif // _include_jitcraft_reference_h_
32.80 +/*
32.81 + * Copyright (C) 2012 David Anderson
32.82 + *
32.83 + * This file is part of SourcePawn.
32.84 + *
32.85 + * SourcePawn is free software: you can redistribute it and/or modify it under
32.86 + * the terms of the GNU General Public License as published by the Free
32.87 + * Software Foundation, either version 3 of the License, or (at your option)
32.88 + * any later version.
32.89 + *
32.90 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
32.91 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32.92 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
32.93 + *
32.94 + * You should have received a copy of the GNU General Public License along with
32.95 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
32.96 + */
32.97 +#ifndef _include_jitcraft_reference_h_
32.98 +#define _include_jitcraft_reference_h_
32.99 +
32.100 +#include "Heap.h"
32.101 +#include "Barriers.h"
32.102 +#include "Stack.h"
32.103 +
32.104 +namespace ke {
32.105 +
32.106 +class Array;
32.107 +class Struct;
32.108 +
32.109 +// A Reference is a typed pointer to another location in memory.
32.110 +class Reference : public Object
32.111 +{
32.112 + void *location_;
32.113 + Barriered<Object> base_;
32.114 +
32.115 + // We do not compute references to objects, so this does not need to be
32.116 + // traced.
32.117 + LocalSlot slot_;
32.118 +
32.119 + public:
32.120 + static Reference *NewStack(Zone *zone, void *location, Heap::Tenure tenure = Heap::Tenure_Default);
32.121 + static Reference *NewStack(Zone *zone, const LocalSlot &slot, Heap::Tenure tenure = Heap::Tenure_Default);
32.122 +
32.123 + int getInt() {
32.124 + return *reinterpret_cast<int *>(location_);
32.125 + }
32.126 + void setInt(int i) {
32.127 + *reinterpret_cast<int *>(location_) = i;
32.128 + }
32.129 + float getFloat() {
32.130 + return *reinterpret_cast<float *>(location_);
32.131 + }
32.132 + void setFloat(float f) {
32.133 + *reinterpret_cast<float *>(location_) = f;
32.134 + }
32.135 +
32.136 + // WARNING! This should only be for Native calls.
32.137 + void *location() {
32.138 + return location_;
32.139 + }
32.140 +
32.141 + // Begin GC Descriptor.
32.142 + static inline size_t offsetOfBase() {
32.143 + return offsetof(Reference, base_);
32.144 + }
32.145 + // End GC Descriptor.
32.146 +
32.147 + static inline Reference *cast(Object *obj) {
32.148 + assert(!obj || obj->is(MapKind_Reference));
32.149 + return reinterpret_cast<Reference *>(obj);
32.150 + }
32.151 +};
32.152 +
32.153 +}
32.154 +
32.155 +#endif // _include_jitcraft_reference_h_
33.1 --- a/src/RootScopes.h Mon Jun 10 00:46:29 2013 +0100
33.2 +++ b/src/RootScopes.h Mon Jun 10 01:04:43 2013 +0100
33.3 @@ -1,106 +1,106 @@
33.4 -/* vim: set ts=4 sw=4 tw=99 et:
33.5 - *
33.6 - * Copyright (C) 2012 David Anderson
33.7 - *
33.8 - * This file is part of SourcePawn.
33.9 - *
33.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
33.11 - * the terms of the GNU General Public License as published by the Free
33.12 - * Software Foundation, either version 3 of the License, or (at your option)
33.13 - * any later version.
33.14 - *
33.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
33.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
33.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
33.18 - *
33.19 - * You should have received a copy of the GNU General Public License along with
33.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
33.21 - */
33.22 -#ifndef _include_jc_root_scopes_h_
33.23 -#define _include_jc_root_scopes_h_
33.24 -
33.25 -#include "../include/keima.h"
33.26 -#include "Objects.h"
33.27 -#include "VirtualObjectVisitor.h"
33.28 -
33.29 -namespace ke {
33.30 -
33.31 -class RootScope;
33.32 -
33.33 -// A RootScopeManager is essentially a specialized PoolAllocator that can
33.34 -// only allocate Object ** entries. It is used to allow huge, temporary
33.35 -// heap data structures like ASTs to hold safe references to objects. When
33.36 -// the data structures is no longer needed, all of the roots are removed
33.37 -// at once.
33.38 -class RootScopeManager
33.39 -{
33.40 - static const size_t kObjectsPerBlock = 4096;
33.41 -
33.42 - struct Block {
33.43 - Object *objects[kObjectsPerBlock];
33.44 - Object **cur;
33.45 - Object **end;
33.46 - Block *prev;
33.47 -
33.48 - Block(Block *prev)
33.49 - : cur(objects),
33.50 - end(objects + kObjectsPerBlock),
33.51 - prev(prev)
33.52 - {
33.53 - }
33.54 - };
33.55 -
33.56 - private:
33.57 - bool grow();
33.58 - void unwindSlow(Object **position);
33.59 -
33.60 - public:
33.61 - RootScopeManager();
33.62 - ~RootScopeManager();
33.63 -
33.64 - Object **position() const {
33.65 - return blocks_->cur;
33.66 - }
33.67 -
33.68 - void unwind(Object **position) {
33.69 - if (position >= blocks_->cur && position <= blocks_->end) {
33.70 - blocks_->cur = position;
33.71 - return;
33.72 - }
33.73 - unwindSlow(position);
33.74 - }
33.75 -
33.76 - Object **make(Object *obj) {
33.77 - assert(scope_);
33.78 - if (blocks_->cur + 1 > blocks_->end) {
33.79 - if (!grow())
33.80 - return NULL;
33.81 - }
33.82 - Object **ptr = blocks_->cur;
33.83 - blocks_->cur++;
33.84 - *ptr = obj;
33.85 - return ptr;
33.86 - }
33.87 -
33.88 - Ke::HandleScope **scope() {
33.89 - return &scope_;
33.90 - }
33.91 -
33.92 - void accept(VirtualObjectVisitor *visitor);
33.93 -
33.94 - private:
33.95 - Block *blocks_;
33.96 - Block first_;
33.97 - Ke::HandleScope *scope_;
33.98 -};
33.99 -
33.100 -class RootScope : public Ke::HandleScope
33.101 -{
33.102 - public:
33.103 - // These are implemented in Zone.h.
33.104 - inline RootScope(Zone *zone);
33.105 -};
33.106 -
33.107 -}
33.108 -
33.109 -#endif // _include_jc_root_scope_h_
33.110 +/* vim: set ts=4 sw=4 tw=99 et:
33.111 + *
33.112 + * Copyright (C) 2012 David Anderson
33.113 + *
33.114 + * This file is part of SourcePawn.
33.115 + *
33.116 + * SourcePawn is free software: you can redistribute it and/or modify it under
33.117 + * the terms of the GNU General Public License as published by the Free
33.118 + * Software Foundation, either version 3 of the License, or (at your option)
33.119 + * any later version.
33.120 + *
33.121 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
33.122 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
33.123 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
33.124 + *
33.125 + * You should have received a copy of the GNU General Public License along with
33.126 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
33.127 + */
33.128 +#ifndef _include_jc_root_scopes_h_
33.129 +#define _include_jc_root_scopes_h_
33.130 +
33.131 +#include "../include/keima.h"
33.132 +#include "Objects.h"
33.133 +#include "VirtualObjectVisitor.h"
33.134 +
33.135 +namespace ke {
33.136 +
33.137 +class RootScope;
33.138 +
33.139 +// A RootScopeManager is essentially a specialized PoolAllocator that can
33.140 +// only allocate Object ** entries. It is used to allow huge, temporary
33.141 +// heap data structures like ASTs to hold safe references to objects. When
33.142 +// the data structures is no longer needed, all of the roots are removed
33.143 +// at once.
33.144 +class RootScopeManager
33.145 +{
33.146 + static const size_t kObjectsPerBlock = 4096;
33.147 +
33.148 + struct Block {
33.149 + Object *objects[kObjectsPerBlock];
33.150 + Object **cur;
33.151 + Object **end;
33.152 + Block *prev;
33.153 +
33.154 + Block(Block *prev)
33.155 + : cur(objects),
33.156 + end(objects + kObjectsPerBlock),
33.157 + prev(prev)
33.158 + {
33.159 + }
33.160 + };
33.161 +
33.162 + private:
33.163 + bool grow();
33.164 + void unwindSlow(Object **position);
33.165 +
33.166 + public:
33.167 + RootScopeManager();
33.168 + ~RootScopeManager();
33.169 +
33.170 + Object **position() const {
33.171 + return blocks_->cur;
33.172 + }
33.173 +
33.174 + void unwind(Object **position) {
33.175 + if (position >= blocks_->cur && position <= blocks_->end) {
33.176 + blocks_->cur = position;
33.177 + return;
33.178 + }
33.179 + unwindSlow(position);
33.180 + }
33.181 +
33.182 + Object **make(Object *obj) {
33.183 + assert(scope_);
33.184 + if (blocks_->cur + 1 > blocks_->end) {
33.185 + if (!grow())
33.186 + return NULL;
33.187 + }
33.188 + Object **ptr = blocks_->cur;
33.189 + blocks_->cur++;
33.190 + *ptr = obj;
33.191 + return ptr;
33.192 + }
33.193 +
33.194 + Ke::HandleScope **scope() {
33.195 + return &scope_;
33.196 + }
33.197 +
33.198 + void accept(VirtualObjectVisitor *visitor);
33.199 +
33.200 + private:
33.201 + Block *blocks_;
33.202 + Block first_;
33.203 + Ke::HandleScope *scope_;
33.204 +};
33.205 +
33.206 +class RootScope : public Ke::HandleScope
33.207 +{
33.208 + public:
33.209 + // These are implemented in Zone.h.
33.210 + inline RootScope(Zone *zone);
33.211 +};
33.212 +
33.213 +}
33.214 +
33.215 +#endif // _include_jc_root_scope_h_
34.1 --- a/src/Stack.h Mon Jun 10 00:46:29 2013 +0100
34.2 +++ b/src/Stack.h Mon Jun 10 01:04:43 2013 +0100
34.3 @@ -1,246 +1,246 @@
34.4 -/* vim: set ts=4 sw=4 tw=99 et:
34.5 - *
34.6 - * Copyright (C) 2012 David Anderson
34.7 - *
34.8 - * This file is part of JITCraft.
34.9 - *
34.10 - * JITCraft is free software: you can redistribute it and/or modify it under
34.11 - * the terms of the GNU General Public License as published by the Free
34.12 - * Software Foundation, either version 3 of the License, or (at your option)
34.13 - * any later version.
34.14 - *
34.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
34.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
34.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
34.18 - *
34.19 - * You should have received a copy of the GNU General Public License along with
34.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
34.21 - */
34.22 -#ifndef _include_jc_stack_h_
34.23 -#define _include_jc_stack_h_
34.24 -
34.25 -#include <stddef.h>
34.26 -#include "Utility.h"
34.27 -#include "Code.h"
34.28 -#include "Functions.h"
34.29 -#include "VirtualObjectVisitor.h"
34.30 -
34.31 -namespace ke {
34.32 -
34.33 -class Object;
34.34 -class Array;
34.35 -class Reference;
34.36 -class Frame;
34.37 -class Stack;
34.38 -class Zone;
34.39 -class Module;
34.40 -
34.41 -union LocalSlot
34.42 -{
34.43 - int i32;
34.44 - float f;
34.45 - Address address;
34.46 - Object *obj;
34.47 - Array *array;
34.48 - Reference *ref;
34.49 - Function *fun;
34.50 - Module *module;
34.51 -};
34.52 -
34.53 -struct Top
34.54 -{
34.55 - LocalSlot *sp;
34.56 - bytecode *pc;
34.57 - Frame *fp;
34.58 -};
34.59 -
34.60 -class Frame
34.61 -{
34.62 - friend class Stack;
34.63 -
34.64 - Frame *prev_;
34.65 - bytecode *prevpc_;
34.66 - union {
34.67 - Function *fun_;
34.68 - Native *native_;
34.69 - Object *callee_;
34.70 - };
34.71 - Code *code_;
34.72 -
34.73 - // Position of the LIFO stack at function entry.
34.74 - Address lifoPosition_;
34.75 -
34.76 - // Loop nesting level, for LIFO stack balancing. LIFO stack balancing
34.77 - // is not strictly required, but it helps to avoid unnecessary waste,
34.78 - // since once the LIFO stack is depleted, we must use the heap instead.
34.79 - unsigned loopDepth_;
34.80 -
34.81 - public:
34.82 - Frame(Frame *prev, bytecode *prevpc, Function *fun, Code *code, Address lifoPosition)
34.83 - : prev_(prev),
34.84 - prevpc_(prevpc),
34.85 - fun_(fun),
34.86 - code_(code),
34.87 - lifoPosition_(lifoPosition),
34.88 - loopDepth_(0)
34.89 - {
34.90 - }
34.91 -
34.92 - Frame(Frame *prev, bytecode *prevpc, Native *native, Address lifoPosition)
34.93 - : prev_(prev),
34.94 - prevpc_(prevpc),
34.95 - native_(native),
34.96 - code_(NULL),
34.97 - lifoPosition_(lifoPosition)
34.98 - {
34.99 - }
34.100 -
34.101 - Address *loopStack() {
34.102 - return reinterpret_cast<Address *>(this + 1);
34.103 - }
34.104 - LocalSlot *locals() {
34.105 - return reinterpret_cast<LocalSlot *>(loopStack() + code_->maxLoopDepth());
34.106 - }
34.107 - LocalSlot *stackBase() {
34.108 - return locals() + code_->nlocals();
34.109 - }
34.110 - Function *fun() const {
34.111 - assert(fun_ && callee_->is(MapKind_Function));
34.112 - return fun_;
34.113 - }
34.114 - Function *maybeFun() const {
34.115 - return (fun_ && callee_->is(MapKind_Function)) ? fun_ : NULL;
34.116 - }
34.117 - bool isNative() const {
34.118 - return callee_ && callee_->is(MapKind_Native);
34.119 - }
34.120 - Native *native() const {
34.121 - assert(isNative());
34.122 - return native_;
34.123 - }
34.124 - Code *code() const {
34.125 - assert(code_);
34.126 - return code_;
34.127 - }
34.128 - Frame *prev() const {
34.129 - return prev_;
34.130 - }
34.131 - bytecode *prevpc() const {
34.132 - return prevpc_;
34.133 - }
34.134 - Address lifoPosition() const {
34.135 - return lifoPosition_;
34.136 - }
34.137 - LocalSlot &arg(unsigned slot) {
34.138 - assert(slot < fun()->nargs());
34.139 - return *(reinterpret_cast<LocalSlot *>(this) - slot - 1);
34.140 - }
34.141 - void enterLoop(Zone *zone);
34.142 - void leaveLoop(Zone *zone);
34.143 - void accept(VirtualObjectVisitor *visitor);
34.144 -};
34.145 -
34.146 -// RAII object for calling a function from C++.
34.147 -class InvokeArgs
34.148 -{
34.149 - friend class Stack;
34.150 -
34.151 - Stack *stack_;
34.152 - LocalSlot *args_;
34.153 - unsigned nargs_;
34.154 -
34.155 - public:
34.156 - InvokeArgs()
34.157 - : stack_(NULL),
34.158 - args_(NULL),
34.159 - nargs_(0)
34.160 - {
34.161 - }
34.162 -
34.163 - ~InvokeArgs();
34.164 -
34.165 - LocalSlot &arg(unsigned index) {
34.166 - assert(index < nargs_);
34.167 - return args_[nargs_ - index - 1];
34.168 - }
34.169 -};
34.170 -
34.171 -// RAII object for calling a native from C++.
34.172 -class NativeArgs
34.173 -{
34.174 - friend class Stack;
34.175 -
34.176 - Stack *stack_;
34.177 - LocalSlot *argsBase_;
34.178 -
34.179 - public:
34.180 - NativeArgs()
34.181 - : stack_(NULL),
34.182 - argsBase_(NULL)
34.183 - {
34.184 - }
34.185 -
34.186 - ~NativeArgs();
34.187 -
34.188 - intptr_t *args() {
34.189 - return reinterpret_cast<intptr_t *>(argsBase_);
34.190 - }
34.191 -};
34.192 -
34.193 -class Stack
34.194 -{
34.195 - friend class InvokeArgs;
34.196 - friend class NativeArgs;
34.197 -
34.198 - private:
34.199 - static const size_t STACK_SIZE = 1024 * 1024;
34.200 -
34.201 - public:
34.202 - Stack(Zone *zone);
34.203 - ~Stack();
34.204 -
34.205 - bool initialize();
34.206 -
34.207 - public:
34.208 - Frame *pushInlineFrame(Handle<Function> fun);
34.209 - Frame *popInlineFrame();
34.210 -
34.211 - bool pushInvokeFrame(Handle<Function> fun, InvokeArgs &args);
34.212 - bool pushModuleFrame(Handle<Module> module, InvokeArgs &args);
34.213 - bool pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc);
34.214 -
34.215 - Top *top() {
34.216 - return &top_;
34.217 - }
34.218 - bool isInCallStack(Handle<Module> module);
34.219 - void accept(VirtualObjectVisitor *visitor);
34.220 -
34.221 - private:
34.222 - void popInvokeFrame(InvokeArgs &args);
34.223 - void popNativeFrame(NativeArgs &args);
34.224 -
34.225 - private:
34.226 - Zone *zone_;
34.227 - char *buffer_;
34.228 - char *end_;
34.229 - Top top_;
34.230 -};
34.231 -
34.232 -class StackIter
34.233 -{
34.234 - bytecode *pc_;
34.235 - Frame *fp_;
34.236 -
34.237 - public:
34.238 - StackIter(Zone *zone);
34.239 -
34.240 - bool done() const;
34.241 - const char *function() const;
34.242 - unsigned lineNumber() const;
34.243 - const char *source() const;
34.244 - void prev();
34.245 -};
34.246 -
34.247 -}
34.248 -
34.249 -#endif // _include_jc_stack_h_
34.250 +/* vim: set ts=4 sw=4 tw=99 et:
34.251 + *
34.252 + * Copyright (C) 2012 David Anderson
34.253 + *
34.254 + * This file is part of JITCraft.
34.255 + *
34.256 + * JITCraft is free software: you can redistribute it and/or modify it under
34.257 + * the terms of the GNU General Public License as published by the Free
34.258 + * Software Foundation, either version 3 of the License, or (at your option)
34.259 + * any later version.
34.260 + *
34.261 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
34.262 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
34.263 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
34.264 + *
34.265 + * You should have received a copy of the GNU General Public License along with
34.266 + * JITCraft. If not, see http://www.gnu.org/licenses/.
34.267 + */
34.268 +#ifndef _include_jc_stack_h_
34.269 +#define _include_jc_stack_h_
34.270 +
34.271 +#include <stddef.h>
34.272 +#include "Utility.h"
34.273 +#include "Code.h"
34.274 +#include "Functions.h"
34.275 +#include "VirtualObjectVisitor.h"
34.276 +
34.277 +namespace ke {
34.278 +
34.279 +class Object;
34.280 +class Array;
34.281 +class Reference;
34.282 +class Frame;
34.283 +class Stack;
34.284 +class Zone;
34.285 +class Module;
34.286 +
34.287 +union LocalSlot
34.288 +{
34.289 + int i32;
34.290 + float f;
34.291 + Address address;
34.292 + Object *obj;
34.293 + Array *array;
34.294 + Reference *ref;
34.295 + Function *fun;
34.296 + Module *module;
34.297 +};
34.298 +
34.299 +struct Top
34.300 +{
34.301 + LocalSlot *sp;
34.302 + bytecode *pc;
34.303 + Frame *fp;
34.304 +};
34.305 +
34.306 +class Frame
34.307 +{
34.308 + friend class Stack;
34.309 +
34.310 + Frame *prev_;
34.311 + bytecode *prevpc_;
34.312 + union {
34.313 + Function *fun_;
34.314 + Native *native_;
34.315 + Object *callee_;
34.316 + };
34.317 + Code *code_;
34.318 +
34.319 + // Position of the LIFO stack at function entry.
34.320 + Address lifoPosition_;
34.321 +
34.322 + // Loop nesting level, for LIFO stack balancing. LIFO stack balancing
34.323 + // is not strictly required, but it helps to avoid unnecessary waste,
34.324 + // since once the LIFO stack is depleted, we must use the heap instead.
34.325 + unsigned loopDepth_;
34.326 +
34.327 + public:
34.328 + Frame(Frame *prev, bytecode *prevpc, Function *fun, Code *code, Address lifoPosition)
34.329 + : prev_(prev),
34.330 + prevpc_(prevpc),
34.331 + fun_(fun),
34.332 + code_(code),
34.333 + lifoPosition_(lifoPosition),
34.334 + loopDepth_(0)
34.335 + {
34.336 + }
34.337 +
34.338 + Frame(Frame *prev, bytecode *prevpc, Native *native, Address lifoPosition)
34.339 + : prev_(prev),
34.340 + prevpc_(prevpc),
34.341 + native_(native),
34.342 + code_(NULL),
34.343 + lifoPosition_(lifoPosition)
34.344 + {
34.345 + }
34.346 +
34.347 + Address *loopStack() {
34.348 + return reinterpret_cast<Address *>(this + 1);
34.349 + }
34.350 + LocalSlot *locals() {
34.351 + return reinterpret_cast<LocalSlot *>(loopStack() + code_->maxLoopDepth());
34.352 + }
34.353 + LocalSlot *stackBase() {
34.354 + return locals() + code_->nlocals();
34.355 + }
34.356 + Function *fun() const {
34.357 + assert(fun_ && callee_->is(MapKind_Function));
34.358 + return fun_;
34.359 + }
34.360 + Function *maybeFun() const {
34.361 + return (fun_ && callee_->is(MapKind_Function)) ? fun_ : NULL;
34.362 + }
34.363 + bool isNative() const {
34.364 + return callee_ && callee_->is(MapKind_Native);
34.365 + }
34.366 + Native *native() const {
34.367 + assert(isNative());
34.368 + return native_;
34.369 + }
34.370 + Code *code() const {
34.371 + assert(code_);
34.372 + return code_;
34.373 + }
34.374 + Frame *prev() const {
34.375 + return prev_;
34.376 + }
34.377 + bytecode *prevpc() const {
34.378 + return prevpc_;
34.379 + }
34.380 + Address lifoPosition() const {
34.381 + return lifoPosition_;
34.382 + }
34.383 + LocalSlot &arg(unsigned slot) {
34.384 + assert(slot < fun()->nargs());
34.385 + return *(reinterpret_cast<LocalSlot *>(this) - slot - 1);
34.386 + }
34.387 + void enterLoop(Zone *zone);
34.388 + void leaveLoop(Zone *zone);
34.389 + void accept(VirtualObjectVisitor *visitor);
34.390 +};
34.391 +
34.392 +// RAII object for calling a function from C++.
34.393 +class InvokeArgs
34.394 +{
34.395 + friend class Stack;
34.396 +
34.397 + Stack *stack_;
34.398 + LocalSlot *args_;
34.399 + unsigned nargs_;
34.400 +
34.401 + public:
34.402 + InvokeArgs()
34.403 + : stack_(NULL),
34.404 + args_(NULL),
34.405 + nargs_(0)
34.406 + {
34.407 + }
34.408 +
34.409 + ~InvokeArgs();
34.410 +
34.411 + LocalSlot &arg(unsigned index) {
34.412 + assert(index < nargs_);
34.413 + return args_[nargs_ - index - 1];
34.414 + }
34.415 +};
34.416 +
34.417 +// RAII object for calling a native from C++.
34.418 +class NativeArgs
34.419 +{
34.420 + friend class Stack;
34.421 +
34.422 + Stack *stack_;
34.423 + LocalSlot *argsBase_;
34.424 +
34.425 + public:
34.426 + NativeArgs()
34.427 + : stack_(NULL),
34.428 + argsBase_(NULL)
34.429 + {
34.430 + }
34.431 +
34.432 + ~NativeArgs();
34.433 +
34.434 + intptr_t *args() {
34.435 + return reinterpret_cast<intptr_t *>(argsBase_);
34.436 + }
34.437 +};
34.438 +
34.439 +class Stack
34.440 +{
34.441 + friend class InvokeArgs;
34.442 + friend class NativeArgs;
34.443 +
34.444 + private:
34.445 + static const size_t STACK_SIZE = 1024 * 1024;
34.446 +
34.447 + public:
34.448 + Stack(Zone *zone);
34.449 + ~Stack();
34.450 +
34.451 + bool initialize();
34.452 +
34.453 + public:
34.454 + Frame *pushInlineFrame(Handle<Function> fun);
34.455 + Frame *popInlineFrame();
34.456 +
34.457 + bool pushInvokeFrame(Handle<Function> fun, InvokeArgs &args);
34.458 + bool pushModuleFrame(Handle<Module> module, InvokeArgs &args);
34.459 + bool pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc);
34.460 +
34.461 + Top *top() {
34.462 + return &top_;
34.463 + }
34.464 + bool isInCallStack(Handle<Module> module);
34.465 + void accept(VirtualObjectVisitor *visitor);
34.466 +
34.467 + private:
34.468 + void popInvokeFrame(InvokeArgs &args);
34.469 + void popNativeFrame(NativeArgs &args);
34.470 +
34.471 + private:
34.472 + Zone *zone_;
34.473 + char *buffer_;
34.474 + char *end_;
34.475 + Top top_;
34.476 +};
34.477 +
34.478 +class StackIter
34.479 +{
34.480 + bytecode *pc_;
34.481 + Frame *fp_;
34.482 +
34.483 + public:
34.484 + StackIter(Zone *zone);
34.485 +
34.486 + bool done() const;
34.487 + const char *function() const;
34.488 + unsigned lineNumber() const;
34.489 + const char *source() const;
34.490 + void prev();
34.491 +};
34.492 +
34.493 +}
34.494 +
34.495 +#endif // _include_jc_stack_h_
35.1 --- a/src/StringPool.cpp Mon Jun 10 00:46:29 2013 +0100
35.2 +++ b/src/StringPool.cpp Mon Jun 10 01:04:43 2013 +0100
35.3 @@ -1,72 +1,72 @@
35.4 -/*
35.5 - * Copyright (C) 2012 David Anderson
35.6 - *
35.7 - * This file is part of JITCraft.
35.8 - *
35.9 - * JITCraft is free software: you can redistribute it and/or modify it under
35.10 - * the terms of the GNU General Public License as published by the Free
35.11 - * Software Foundation, either version 3 of the License, or (at your option)
35.12 - * any later version.
35.13 - *
35.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
35.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
35.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
35.17 - *
35.18 - * You should have received a copy of the GNU General Public License along with
35.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
35.20 - */
35.21 -#include "Zone.h"
35.22 -#include "StringPool.h"
35.23 -#include "Strings.h"
35.24 -#include "Spaces.h"
35.25 -#include "Spaces-inl.h"
35.26 -#include "Heap-inl.h"
35.27 -
35.28 -using namespace ke;
35.29 -
35.30 -StringPool::StringPool(Zone *zone)
35.31 - : zone_(zone),
35.32 - set_(ZoneAllocatorPolicy())
35.33 -{
35.34 -}
35.35 -
35.36 -StringPool::~StringPool()
35.37 -{
35.38 -}
35.39 -
35.40 -bool
35.41 -StringPool::initialize()
35.42 -{
35.43 - if (!set_.init(32))
35.44 - return false;
35.45 - return true;
35.46 -}
35.47 -
35.48 -String *
35.49 -StringPool::add(const char *str, size_t length)
35.50 -{
35.51 - StringSet::Insert i = set_.findForAdd(CharsAndLength(str, length));
35.52 - if (i.found())
35.53 - return *i;
35.54 -
35.55 - Local<String> obj(zone_, String::New(zone_, str, length, Heap::Tenure_Old));
35.56 - if (!obj)
35.57 - return NULL;
35.58 -
35.59 - set_.add(i, obj);
35.60 - return obj;
35.61 -}
35.62 -
35.63 -void
35.64 -StringPool::sweep()
35.65 -{
35.66 - for (StringSet::iterator i(&set_); !i.empty(); i.next()) {
35.67 - String *obj = *i;
35.68 - MarkBit bits = HeapChunk::GetMarkBit(obj);
35.69 - if (HeapChunk::IsWhite(bits))
35.70 - i.erase();
35.71 - else
35.72 - assert(HeapChunk::IsBlack(bits));
35.73 - }
35.74 - set_.checkDensity();
35.75 -}
35.76 +/*
35.77 + * Copyright (C) 2012 David Anderson
35.78 + *
35.79 + * This file is part of JITCraft.
35.80 + *
35.81 + * JITCraft is free software: you can redistribute it and/or modify it under
35.82 + * the terms of the GNU General Public License as published by the Free
35.83 + * Software Foundation, either version 3 of the License, or (at your option)
35.84 + * any later version.
35.85 + *
35.86 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
35.87 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
35.88 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
35.89 + *
35.90 + * You should have received a copy of the GNU General Public License along with
35.91 + * JITCraft. If not, see http://www.gnu.org/licenses/.
35.92 + */
35.93 +#include "Zone.h"
35.94 +#include "StringPool.h"
35.95 +#include "Strings.h"
35.96 +#include "Spaces.h"
35.97 +#include "Spaces-inl.h"
35.98 +#include "Heap-inl.h"
35.99 +
35.100 +using namespace ke;
35.101 +
35.102 +StringPool::StringPool(Zone *zone)
35.103 + : zone_(zone),
35.104 + set_(ZoneAllocatorPolicy())
35.105 +{
35.106 +}
35.107 +
35.108 +StringPool::~StringPool()
35.109 +{
35.110 +}
35.111 +
35.112 +bool
35.113 +StringPool::initialize()
35.114 +{
35.115 + if (!set_.init(32))
35.116 + return false;
35.117 + return true;
35.118 +}
35.119 +
35.120 +String *
35.121 +StringPool::add(const char *str, size_t length)
35.122 +{
35.123 + StringSet::Insert i = set_.findForAdd(CharsAndLength(str, length));
35.124 + if (i.found())
35.125 + return *i;
35.126 +
35.127 + Local<String> obj(zone_, String::New(zone_, str, length, Heap::Tenure_Old));
35.128 + if (!obj)
35.129 + return NULL;
35.130 +
35.131 + set_.add(i, obj);
35.132 + return obj;
35.133 +}
35.134 +
35.135 +void
35.136 +StringPool::sweep()
35.137 +{
35.138 + for (StringSet::iterator i(&set_); !i.empty(); i.next()) {
35.139 + String *obj = *i;
35.140 + MarkBit bits = HeapChunk::GetMarkBit(obj);
35.141 + if (HeapChunk::IsWhite(bits))
35.142 + i.erase();
35.143 + else
35.144 + assert(HeapChunk::IsBlack(bits));
35.145 + }
35.146 + set_.checkDensity();
35.147 +}
36.1 --- a/src/StringPool.h Mon Jun 10 00:46:29 2013 +0100
36.2 +++ b/src/StringPool.h Mon Jun 10 01:04:43 2013 +0100
36.3 @@ -1,68 +1,68 @@
36.4 -/* vim: set ts=4 sw=4 tw=99 et:
36.5 - *
36.6 - * Copyright (C) 2012 David Anderson
36.7 - *
36.8 - * This file is part of SourcePawn.
36.9 - *
36.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
36.11 - * the terms of the GNU General Public License as published by the Free
36.12 - * Software Foundation, either version 3 of the License, or (at your option)
36.13 - * any later version.
36.14 - *
36.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
36.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
36.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
36.18 - *
36.19 - * You should have received a copy of the GNU General Public License along with
36.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
36.21 - */
36.22 -#ifndef _include_jitcraft_string_pool_h_
36.23 -#define _include_jitcraft_string_pool_h_
36.24 -
36.25 -#include <string.h>
36.26 -#include "AllocatorPolicies.h"
36.27 -#include "HashTable.h"
36.28 -#include "Strings.h"
36.29 -
36.30 -namespace ke {
36.31 -
36.32 -class Zone;
36.33 -class String;
36.34 -
36.35 -// Guarantee that strings with the same contents will map to one pointer.
36.36 -class StringPool
36.37 -{
36.38 - struct Policy
36.39 - {
36.40 - typedef String * Payload;
36.41 -
36.42 - static uint32 hash(const CharsAndLength &key) {
36.43 - return HashCharSequence(key.str(), key.length());
36.44 - }
36.45 -
36.46 - static bool matches(const CharsAndLength &key, String *string) {
36.47 - if (string->length() != key.length())
36.48 - return false;
36.49 - return memcmp(string->chars(), key.str(), key.length() * sizeof(char)) == 0;
36.50 - }
36.51 - };
36.52 -
36.53 - typedef HashTable<Policy, ZoneAllocatorPolicy> StringSet;
36.54 -
36.55 - public:
36.56 - StringPool(Zone *zone);
36.57 - ~StringPool();
36.58 - bool initialize();
36.59 -
36.60 - public:
36.61 - String *add(const char *str, size_t len);
36.62 - void sweep();
36.63 -
36.64 - private:
36.65 - Zone *zone_;
36.66 - StringSet set_;
36.67 -};
36.68 -
36.69 -}
36.70 -
36.71 -#endif // _include_jitcraft_string_pool_h_
36.72 +/* vim: set ts=4 sw=4 tw=99 et:
36.73 + *
36.74 + * Copyright (C) 2012 David Anderson
36.75 + *
36.76 + * This file is part of SourcePawn.
36.77 + *
36.78 + * SourcePawn is free software: you can redistribute it and/or modify it under
36.79 + * the terms of the GNU General Public License as published by the Free
36.80 + * Software Foundation, either version 3 of the License, or (at your option)
36.81 + * any later version.
36.82 + *
36.83 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
36.84 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
36.85 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
36.86 + *
36.87 + * You should have received a copy of the GNU General Public License along with
36.88 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
36.89 + */
36.90 +#ifndef _include_jitcraft_string_pool_h_
36.91 +#define _include_jitcraft_string_pool_h_
36.92 +
36.93 +#include <string.h>
36.94 +#include "AllocatorPolicies.h"
36.95 +#include "HashTable.h"
36.96 +#include "Strings.h"
36.97 +
36.98 +namespace ke {
36.99 +
36.100 +class Zone;
36.101 +class String;
36.102 +
36.103 +// Guarantee that strings with the same contents will map to one pointer.
36.104 +class StringPool
36.105 +{
36.106 + struct Policy
36.107 + {
36.108 + typedef String * Payload;
36.109 +
36.110 + static uint32 hash(const CharsAndLength &key) {
36.111 + return HashCharSequence(key.str(), key.length());
36.112 + }
36.113 +
36.114 + static bool matches(const CharsAndLength &key, String *string) {
36.115 + if (string->length() != key.length())
36.116 + return false;
36.117 + return memcmp(string->chars(), key.str(), key.length() * sizeof(char)) == 0;
36.118 + }
36.119 + };
36.120 +
36.121 + typedef HashTable<Policy, ZoneAllocatorPolicy> StringSet;
36.122 +
36.123 + public:
36.124 + StringPool(Zone *zone);
36.125 + ~StringPool();
36.126 + bool initialize();
36.127 +
36.128 + public:
36.129 + String *add(const char *str, size_t len);
36.130 + void sweep();
36.131 +
36.132 + private:
36.133 + Zone *zone_;
36.134 + StringSet set_;
36.135 +};
36.136 +
36.137 +}
36.138 +
36.139 +#endif // _include_jitcraft_string_pool_h_
37.1 --- a/src/Strings.cpp Mon Jun 10 00:46:29 2013 +0100
37.2 +++ b/src/Strings.cpp Mon Jun 10 01:04:43 2013 +0100
37.3 @@ -1,44 +1,44 @@
37.4 -/* vim: set ts=4 sw=4 tw=99 et:
37.5 - *
37.6 - * Copyright (C) 2012 David Anderson
37.7 - *
37.8 - * This file is part of JITCraft.
37.9 - *
37.10 - * JITCraft is free software: you can redistribute it and/or modify it under
37.11 - * the terms of the GNU General Public License as published by the Free
37.12 - * Software Foundation, either version 3 of the License, or (at your option)
37.13 - * any later version.
37.14 - *
37.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
37.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
37.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
37.18 - *
37.19 - * You should have received a copy of the GNU General Public License along with
37.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
37.21 - */
37.22 -#include <string.h>
37.23 -#include "Strings.h"
37.24 -#include "Zone.h"
37.25 -#include "Heap-inl.h"
37.26 -
37.27 -using namespace ke;
37.28 -
37.29 -String *
37.30 -String::New(Zone *zone, const char *from, Heap::Tenure tenure)
37.31 -{
37.32 - return New(zone, from, strlen(from), tenure);
37.33 -}
37.34 -
37.35 -String *
37.36 -String::New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure)
37.37 -{
37.38 - size_t bytes = SizeFor(length);
37.39 - Local<String> string(zone, String::cast(zone->allocate(MapKind_String, bytes, tenure)));
37.40 - if (!string)
37.41 - return NULL;
37.42 -
37.43 - string->length_ = length;
37.44 - memcpy(string->chars(), from, length + 1);
37.45 -
37.46 - return string;
37.47 -}
37.48 +/* vim: set ts=4 sw=4 tw=99 et:
37.49 + *
37.50 + * Copyright (C) 2012 David Anderson
37.51 + *
37.52 + * This file is part of JITCraft.
37.53 + *
37.54 + * JITCraft is free software: you can redistribute it and/or modify it under
37.55 + * the terms of the GNU General Public License as published by the Free
37.56 + * Software Foundation, either version 3 of the License, or (at your option)
37.57 + * any later version.
37.58 + *
37.59 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
37.60 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
37.61 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
37.62 + *
37.63 + * You should have received a copy of the GNU General Public License along with
37.64 + * JITCraft. If not, see http://www.gnu.org/licenses/.
37.65 + */
37.66 +#include <string.h>
37.67 +#include "Strings.h"
37.68 +#include "Zone.h"
37.69 +#include "Heap-inl.h"
37.70 +
37.71 +using namespace ke;
37.72 +
37.73 +String *
37.74 +String::New(Zone *zone, const char *from, Heap::Tenure tenure)
37.75 +{
37.76 + return New(zone, from, strlen(from), tenure);
37.77 +}
37.78 +
37.79 +String *
37.80 +String::New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure)
37.81 +{
37.82 + size_t bytes = SizeFor(length);
37.83 + Local<String> string(zone, String::cast(zone->allocate(MapKind_String, bytes, tenure)));
37.84 + if (!string)
37.85 + return NULL;
37.86 +
37.87 + string->length_ = length;
37.88 + memcpy(string->chars(), from, length + 1);
37.89 +
37.90 + return string;
37.91 +}
38.1 --- a/src/Strings.h Mon Jun 10 00:46:29 2013 +0100
38.2 +++ b/src/Strings.h Mon Jun 10 01:04:43 2013 +0100
38.3 @@ -1,80 +1,80 @@
38.4 -/* vim: set ts=4 sw=4 tw=99 et:
38.5 - *
38.6 - * Copyright (C) 2012 David Anderson
38.7 - *
38.8 - * This file is part of JITCraft.
38.9 - *
38.10 - * JITCraft is free software: you can redistribute it and/or modify it under
38.11 - * the terms of the GNU General Public License as published by the Free
38.12 - * Software Foundation, either version 3 of the License, or (at your option)
38.13 - * any later version.
38.14 - *
38.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
38.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
38.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
38.18 - *
38.19 - * You should have received a copy of the GNU General Public License along with
38.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
38.21 - */
38.22 -#ifndef _include_jitcraft_string_h_
38.23 -#define _include_jitcraft_string_h_
38.24 -
38.25 -#include "Heap.h"
38.26 -
38.27 -namespace ke {
38.28 -
38.29 -// A fixed-length string containing UTF-8 characters.
38.30 -class String : public Object
38.31 -{
38.32 - uint32 length_;
38.33 -
38.34 - public:
38.35 - static String *New(Zone *zone, const char *from, Heap::Tenure tenure = Heap::Tenure_Default);
38.36 - static String *New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure = Heap::Tenure_Default);
38.37 -
38.38 - unsigned length() {
38.39 - return length_;
38.40 - }
38.41 - char *chars() {
38.42 - return reinterpret_cast<char *>(this + 1);
38.43 - }
38.44 - char *chars(Zone *zone) {
38.45 - return chars();
38.46 - }
38.47 - size_t objSize() {
38.48 - return SizeFor(length());
38.49 - }
38.50 -
38.51 - static size_t SizeFor(unsigned length) {
38.52 - return sizeof(String) + sizeof(char) * (length + 1);
38.53 - }
38.54 -
38.55 - static inline String *cast(Object *obj) {
38.56 - assert(!obj || obj->is(MapKind_String));
38.57 - return reinterpret_cast<String *>(obj);
38.58 - }
38.59 -};
38.60 -
38.61 -class CharsAndLength
38.62 -{
38.63 - const char *str_;
38.64 - size_t length_;
38.65 -
38.66 - public:
38.67 - CharsAndLength(const char *str, size_t length)
38.68 - : str_(str),
38.69 - length_(length)
38.70 - {
38.71 - }
38.72 -
38.73 - const char *str() const {
38.74 - return str_;
38.75 - }
38.76 - size_t length() const {
38.77 - return length_;
38.78 - }
38.79 -};
38.80 -
38.81 -}
38.82 -
38.83 -#endif // _include_jitcraft_string_h_
38.84 +/* vim: set ts=4 sw=4 tw=99 et:
38.85 + *
38.86 + * Copyright (C) 2012 David Anderson
38.87 + *
38.88 + * This file is part of JITCraft.
38.89 + *
38.90 + * JITCraft is free software: you can redistribute it and/or modify it under
38.91 + * the terms of the GNU General Public License as published by the Free
38.92 + * Software Foundation, either version 3 of the License, or (at your option)
38.93 + * any later version.
38.94 + *
38.95 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
38.96 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
38.97 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
38.98 + *
38.99 + * You should have received a copy of the GNU General Public License along with
38.100 + * JITCraft. If not, see http://www.gnu.org/licenses/.
38.101 + */
38.102 +#ifndef _include_jitcraft_string_h_
38.103 +#define _include_jitcraft_string_h_
38.104 +
38.105 +#include "Heap.h"
38.106 +
38.107 +namespace ke {
38.108 +
38.109 +// A fixed-length string containing UTF-8 characters.
38.110 +class String : public Object
38.111 +{
38.112 + uint32 length_;
38.113 +
38.114 + public:
38.115 + static String *New(Zone *zone, const char *from, Heap::Tenure tenure = Heap::Tenure_Default);
38.116 + static String *New(Zone *zone, const char *from, size_t length, Heap::Tenure tenure = Heap::Tenure_Default);
38.117 +
38.118 + unsigned length() {
38.119 + return length_;
38.120 + }
38.121 + char *chars() {
38.122 + return reinterpret_cast<char *>(this + 1);
38.123 + }
38.124 + char *chars(Zone *zone) {
38.125 + return chars();
38.126 + }
38.127 + size_t objSize() {
38.128 + return SizeFor(length());
38.129 + }
38.130 +
38.131 + static size_t SizeFor(unsigned length) {
38.132 + return sizeof(String) + sizeof(char) * (length + 1);
38.133 + }
38.134 +
38.135 + static inline String *cast(Object *obj) {
38.136 + assert(!obj || obj->is(MapKind_String));
38.137 + return reinterpret_cast<String *>(obj);
38.138 + }
38.139 +};
38.140 +
38.141 +class CharsAndLength
38.142 +{
38.143 + const char *str_;
38.144 + size_t length_;
38.145 +
38.146 + public:
38.147 + CharsAndLength(const char *str, size_t length)
38.148 + : str_(str),
38.149 + length_(length)
38.150 + {
38.151 + }
38.152 +
38.153 + const char *str() const {
38.154 + return str_;
38.155 + }
38.156 + size_t length() const {
38.157 + return length_;
38.158 + }
38.159 +};
38.160 +
38.161 +}
38.162 +
38.163 +#endif // _include_jitcraft_string_h_
39.1 --- a/src/Structures.cpp Mon Jun 10 00:46:29 2013 +0100
39.2 +++ b/src/Structures.cpp Mon Jun 10 01:04:43 2013 +0100
39.3 @@ -1,205 +1,205 @@
39.4 -/* vim: set ts=4 sw=4 tw=99 et:
39.5 - *
39.6 - * Copyright (C) 2012 David Anderson
39.7 - *
39.8 - * This file is part of SourcePawn.
39.9 - *
39.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
39.11 - * the terms of the GNU General Public License as published by the Free
39.12 - * Software Foundation, either version 3 of the License, or (at your option)
39.13 - * any later version.
39.14 - *
39.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
39.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
39.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
39.18 - *
39.19 - * You should have received a copy of the GNU General Public License along with
39.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
39.21 - */
39.22 -#include <string.h>
39.23 -#include "Structures.h"
39.24 -#include "Zone.h"
39.25 -#include "Types.h"
39.26 -#include "Array.h"
39.27 -#include "Spaces-inl.h"
39.28 -#include "Heap-inl.h"
39.29 -
39.30 -using namespace ke;
39.31 -
39.32 -StructureBufferBuilder::StructureBufferBuilder()
39.33 - : size_(0)
39.34 -{
39.35 -}
39.36 -
39.37 -bool
39.38 -StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
39.39 -{
39.40 - *offset = size_;
39.41 -
39.42 - if (!type->isTraceable()) {
39.43 - // For now, assume the alignment of all primitive storage is 4 bytes,
39.44 - // and that all need <= 4 bytes of storage.
39.45 - assert(type->isInt32() ||
39.46 - type->isFloat() ||
39.47 - type->isBool() ||
39.48 - type->isChar() ||
39.49 - type->isEnum());
39.50 - size_ += 4;
39.51 - return true;
39.52 - }
39.53 -
39.54 - if (!offsets_.append(size_))
39.55 - return false;
39.56 -
39.57 - size_ += sizeof(Object *);
39.58 - return true;
39.59 -}
39.60 -
39.61 -Descriptor *
39.62 -Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility)
39.63 -{
39.64 - Local<Descriptor> desc(zone,
39.65 - Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
39.66 - if (!desc)
39.67 - return NULL;
39.68 -
39.69 - desc->name_ = name;
39.70 - desc->type_ = type;
39.71 - desc->offset_ = unsigned(-1);
39.72 - desc->visibility_ = visibility;
39.73 - return desc;
39.74 -}
39.75 -
39.76 -StructMap *
39.77 -StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
39.78 -{
39.79 - Vector<unsigned> composedIndexes;
39.80 - for (size_t i = 0; i < type->fields()->length(); i++) {
39.81 - Descriptor *desc = Descriptor::cast(type->fields()->at(i));
39.82 - if (desc->type()->isArray() || desc->type()->isStruct()) {
39.83 - if (!composedIndexes.append(i))
39.84 - return NULL;
39.85 - }
39.86 - }
39.87 -
39.88 - Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
39.89 - if (!composed)
39.90 - return NULL;
39.91 -
39.92 - for (size_t i = 0; i < composedIndexes.length(); i++) {
39.93 - Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
39.94 - composed->set(zone, i, desc);
39.95 - }
39.96 -
39.97 - size_t bytesNeeded = sizeof(StructMap) +
39.98 - (builder.traceableOffsetCount() * sizeof(unsigned));
39.99 -
39.100 - Local<StructMap> map(zone);
39.101 - map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
39.102 - if (!map)
39.103 - return NULL;
39.104 -
39.105 - map->structureSize_ = builder.structureSize();
39.106 - map->traceOffsetCount_ = builder.traceableOffsetCount();
39.107 - map->type_ = type;
39.108 - map->composed_ = composed;
39.109 - memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
39.110 - sizeof(unsigned) * builder.traceableOffsetCount());
39.111 -
39.112 - return map;
39.113 -}
39.114 -
39.115 -Struct *
39.116 -Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
39.117 -{
39.118 - size_t bytesNeeded = SizeFor(map);
39.119 -
39.120 - Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
39.121 - if (!obj)
39.122 - return NULL;
39.123 -
39.124 - memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct)));
39.125 -
39.126 - // Initialize any sub-structures. Right now, this is performed as part of
39.127 - // struct allocation, rather than inlined in bytecode, for simplicity.
39.128 - if (map->composed()) {
39.129 - Local<Descriptor> desc(zone);
39.130 - Local<Object> child(zone);
39.131 - Local<StructMap> childStructMap(zone);
39.132 - Local<ArrayMap> childArrayMap(zone);
39.133 -
39.134 - for (unsigned i = 0; i < map->composed()->length(); i++) {
39.135 - desc = Descriptor::cast(map->composed()->at(i));
39.136 -
39.137 - if (desc->type()->isStruct()) {
39.138 - childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
39.139 - child = Struct::New(zone, childStructMap, tenure);
39.140 - } else if (desc->type()->isArray()) {
39.141 - // :TODO: don't create empty arrays for ref slots here.
39.142 - // Instead, make a separate Initialize function, so we
39.143 - // can avoid double-creating arrays for module globals.
39.144 - // (const char:x[] = "x")
39.145 - ArrayType *type = ArrayType::cast(desc->type());
39.146 - childArrayMap = ArrayMap::cast(type->newMap());
39.147 - if (type->isFixedLength())
39.148 - child = Array::NewFixed(zone, childArrayMap, tenure);
39.149 - else
39.150 - child = Array::NewEmpty(zone, childArrayMap, tenure);
39.151 - }
39.152 - if (!child)
39.153 - return NULL;
39.154 -
39.155 - obj->set(zone, desc, child);
39.156 - }
39.157 - }
39.158 -
39.159 - return obj;
39.160 -}
39.161 -
39.162 -bool
39.163 -Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
39.164 -{
39.165 - assert(left->map()->type() == right->map()->type());
39.166 -
39.167 - Local<StructType> type(zone, StructType::cast(left->map()->type()));
39.168 - Local<Struct> leftStruct(zone);
39.169 - Local<Struct> rightStruct(zone);
39.170 - Local<Array> leftArray(zone);
39.171 - Local<Array> rightArray(zone);
39.172 - for (unsigned i = 0; i < type->fields()->length(); i++) {
39.173 - Descriptor *desc = Descriptor::cast(type->fields()->at(i));
39.174 -
39.175 - // If the field is a struct, we need to deep-copy.
39.176 - if (desc->type()->isStruct()) {
39.177 - leftStruct = Struct::cast(left->get<Object *>(desc));
39.178 - rightStruct = Struct::cast(right->get<Object *>(desc));
39.179 - if (!Struct::Copy(zone, leftStruct, rightStruct))
39.180 - return false;
39.181 - } else if (desc->type()->isArray()) {
39.182 - leftArray = Array::cast(left->get<Object *>(desc));
39.183 - rightArray = Array::cast(right->get<Object *>(desc));
39.184 - if (!Array::ShallowCopy(zone, leftArray, rightArray))
39.185 - return false;
39.186 - } else if (desc->type()->isTraceable()) {
39.187 - Object *obj = right->get<Object *>(desc);
39.188 - left->set(zone, desc, obj);
39.189 - } else {
39.190 - switch (desc->type()->pod()) {
39.191 - case PrimitiveType_Int32:
39.192 - case PrimitiveType_Char:
39.193 - case PrimitiveType_Bool:
39.194 - left->set(desc, right->get<int>(desc));
39.195 - break;
39.196 -
39.197 - case PrimitiveType_Float:
39.198 - left->set(desc, right->get<float>(desc));
39.199 - break;
39.200 -
39.201 - default:
39.202 - assert(false);
39.203 - }
39.204 - }
39.205 - }
39.206 -
39.207 - return true;
39.208 +/* vim: set ts=4 sw=4 tw=99 et:
39.209 + *
39.210 + * Copyright (C) 2012 David Anderson
39.211 + *
39.212 + * This file is part of SourcePawn.
39.213 + *
39.214 + * SourcePawn is free software: you can redistribute it and/or modify it under
39.215 + * the terms of the GNU General Public License as published by the Free
39.216 + * Software Foundation, either version 3 of the License, or (at your option)
39.217 + * any later version.
39.218 + *
39.219 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
39.220 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
39.221 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
39.222 + *
39.223 + * You should have received a copy of the GNU General Public License along with
39.224 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
39.225 + */
39.226 +#include <string.h>
39.227 +#include "Structures.h"
39.228 +#include "Zone.h"
39.229 +#include "Types.h"
39.230 +#include "Array.h"
39.231 +#include "Spaces-inl.h"
39.232 +#include "Heap-inl.h"
39.233 +
39.234 +using namespace ke;
39.235 +
39.236 +StructureBufferBuilder::StructureBufferBuilder()
39.237 + : size_(0)
39.238 +{
39.239 +}
39.240 +
39.241 +bool
39.242 +StructureBufferBuilder::add(Handle<Type> type, unsigned *offset)
39.243 +{
39.244 + *offset = size_;
39.245 +
39.246 + if (!type->isTraceable()) {
39.247 + // For now, assume the alignment of all primitive storage is 4 bytes,
39.248 + // and that all need <= 4 bytes of storage.
39.249 + assert(type->isInt32() ||
39.250 + type->isFloat() ||
39.251 + type->isBool() ||
39.252 + type->isChar() ||
39.253 + type->isEnum());
39.254 + size_ += 4;
39.255 + return true;
39.256 + }
39.257 +
39.258 + if (!offsets_.append(size_))
39.259 + return false;
39.260 +
39.261 + size_ += sizeof(Object *);
39.262 + return true;
39.263 +}
39.264 +
39.265 +Descriptor *
39.266 +Descriptor::New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility)
39.267 +{
39.268 + Local<Descriptor> desc(zone,
39.269 + Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old)));
39.270 + if (!desc)
39.271 + return NULL;
39.272 +
39.273 + desc->name_ = name;
39.274 + desc->type_ = type;
39.275 + desc->offset_ = unsigned(-1);
39.276 + desc->visibility_ = visibility;
39.277 + return desc;
39.278 +}
39.279 +
39.280 +StructMap *
39.281 +StructMap::New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type)
39.282 +{
39.283 + Vector<unsigned> composedIndexes;
39.284 + for (size_t i = 0; i < type->fields()->length(); i++) {
39.285 + Descriptor *desc = Descriptor::cast(type->fields()->at(i));
39.286 + if (desc->type()->isArray() || desc->type()->isStruct()) {
39.287 + if (!composedIndexes.append(i))
39.288 + return NULL;
39.289 + }
39.290 + }
39.291 +
39.292 + Local<FixedArray> composed(zone, FixedArray::New(zone, composedIndexes.length(), Heap::Tenure_Old));
39.293 + if (!composed)
39.294 + return NULL;
39.295 +
39.296 + for (size_t i = 0; i < composedIndexes.length(); i++) {
39.297 + Descriptor *desc = Descriptor::cast(type->fields()->at(composedIndexes[i]));
39.298 + composed->set(zone, i, desc);
39.299 + }
39.300 +
39.301 + size_t bytesNeeded = sizeof(StructMap) +
39.302 + (builder.traceableOffsetCount() * sizeof(unsigned));
39.303 +
39.304 + Local<StructMap> map(zone);
39.305 + map = StructMap::cast(zone->allocateMap(MapKind_Struct, bytesNeeded, MapKind_MetaStruct));
39.306 + if (!map)
39.307 + return NULL;
39.308 +
39.309 + map->structureSize_ = builder.structureSize();
39.310 + map->traceOffsetCount_ = builder.traceableOffsetCount();
39.311 + map->type_ = type;
39.312 + map->composed_ = composed;
39.313 + memcpy(const_cast<unsigned *>(map->traceOffsets()), builder.offsets(),
39.314 + sizeof(unsigned) * builder.traceableOffsetCount());
39.315 +
39.316 + return map;
39.317 +}
39.318 +
39.319 +Struct *
39.320 +Struct::New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure)
39.321 +{
39.322 + size_t bytesNeeded = SizeFor(map);
39.323 +
39.324 + Local<Struct> obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure)));
39.325 + if (!obj)
39.326 + return NULL;
39.327 +
39.328 + memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct)));
39.329 +
39.330 + // Initialize any sub-structures. Right now, this is performed as part of
39.331 + // struct allocation, rather than inlined in bytecode, for simplicity.
39.332 + if (map->composed()) {
39.333 + Local<Descriptor> desc(zone);
39.334 + Local<Object> child(zone);
39.335 + Local<StructMap> childStructMap(zone);
39.336 + Local<ArrayMap> childArrayMap(zone);
39.337 +
39.338 + for (unsigned i = 0; i < map->composed()->length(); i++) {
39.339 + desc = Descriptor::cast(map->composed()->at(i));
39.340 +
39.341 + if (desc->type()->isStruct()) {
39.342 + childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
39.343 + child = Struct::New(zone, childStructMap, tenure);
39.344 + } else if (desc->type()->isArray()) {
39.345 + // :TODO: don't create empty arrays for ref slots here.
39.346 + // Instead, make a separate Initialize function, so we
39.347 + // can avoid double-creating arrays for module globals.
39.348 + // (const char:x[] = "x")
39.349 + ArrayType *type = ArrayType::cast(desc->type());
39.350 + childArrayMap = ArrayMap::cast(type->newMap());
39.351 + if (type->isFixedLength())
39.352 + child = Array::NewFixed(zone, childArrayMap, tenure);
39.353 + else
39.354 + child = Array::NewEmpty(zone, childArrayMap, tenure);
39.355 + }
39.356 + if (!child)
39.357 + return NULL;
39.358 +
39.359 + obj->set(zone, desc, child);
39.360 + }
39.361 + }
39.362 +
39.363 + return obj;
39.364 +}
39.365 +
39.366 +bool
39.367 +Struct::Copy(Zone *zone, Handle<Struct> left, Handle<Struct> right)
39.368 +{
39.369 + assert(left->map()->type() == right->map()->type());
39.370 +
39.371 + Local<StructType> type(zone, StructType::cast(left->map()->type()));
39.372 + Local<Struct> leftStruct(zone);
39.373 + Local<Struct> rightStruct(zone);
39.374 + Local<Array> leftArray(zone);
39.375 + Local<Array> rightArray(zone);
39.376 + for (unsigned i = 0; i < type->fields()->length(); i++) {
39.377 + Descriptor *desc = Descriptor::cast(type->fields()->at(i));
39.378 +
39.379 + // If the field is a struct, we need to deep-copy.
39.380 + if (desc->type()->isStruct()) {
39.381 + leftStruct = Struct::cast(left->get<Object *>(desc));
39.382 + rightStruct = Struct::cast(right->get<Object *>(desc));
39.383 + if (!Struct::Copy(zone, leftStruct, rightStruct))
39.384 + return false;
39.385 + } else if (desc->type()->isArray()) {
39.386 + leftArray = Array::cast(left->get<Object *>(desc));
39.387 + rightArray = Array::cast(right->get<Object *>(desc));
39.388 + if (!Array::ShallowCopy(zone, leftArray, rightArray))
39.389 + return false;
39.390 + } else if (desc->type()->isTraceable()) {
39.391 + Object *obj = right->get<Object *>(desc);
39.392 + left->set(zone, desc, obj);
39.393 + } else {
39.394 + switch (desc->type()->pod()) {
39.395 + case PrimitiveType_Int32:
39.396 + case PrimitiveType_Char:
39.397 + case PrimitiveType_Bool:
39.398 + left->set(desc, right->get<int>(desc));
39.399 + break;
39.400 +
39.401 + case PrimitiveType_Float:
39.402 + left->set(desc, right->get<float>(desc));
39.403 + break;
39.404 +
39.405 + default:
39.406 + assert(false);
39.407 + }
39.408 + }
39.409 + }
39.410 +
39.411 + return true;
39.412 }
39.413 \ No newline at end of file
40.1 --- a/src/Structures.h Mon Jun 10 00:46:29 2013 +0100
40.2 +++ b/src/Structures.h Mon Jun 10 01:04:43 2013 +0100
40.3 @@ -1,215 +1,215 @@
40.4 -/* vim: set ts=4 sw=4 tw=99 et:
40.5 - *
40.6 - * Copyright (C) 2012 David Anderson
40.7 - *
40.8 - * This file is part of SourcePawn.
40.9 - *
40.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
40.11 - * the terms of the GNU General Public License as published by the Free
40.12 - * Software Foundation, either version 3 of the License, or (at your option)
40.13 - * any later version.
40.14 - *
40.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
40.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
40.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
40.18 - *
40.19 - * You should have received a copy of the GNU General Public License along with
40.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
40.21 - */
40.22 -#ifndef _include_jc_structure_h_
40.23 -#define _include_jc_structure_h_
40.24 -
40.25 -#include "Objects.h"
40.26 -#include "Handles.h"
40.27 -#include "Vector.h"
40.28 -#include "Heap.h"
40.29 -
40.30 -namespace ke {
40.31 -
40.32 -class Type;
40.33 -class String;
40.34 -class FixedArray;
40.35 -class StructType;
40.36 -
40.37 -// When describing composite structures, the GC must be able to trace interior
40.38 -// references to Objects. To make this possible, maps that describe composite
40.39 -// structures must provide a list of offsets into their objects that are
40.40 -// traceable. StructureBufferBuilder assists with this.
40.41 -class StructureBufferBuilder
40.42 -{
40.43 - public:
40.44 - StructureBufferBuilder();
40.45 -
40.46 - bool add(Handle<Type> type, unsigned *offset);
40.47 -
40.48 - unsigned structureSize() const {
40.49 - return size_;
40.50 - }
40.51 - unsigned traceableOffsetCount() const {
40.52 - return offsets_.length();
40.53 - }
40.54 - const unsigned *offsets() const {
40.55 - return offsets_.buffer();
40.56 - }
40.57 -
40.58 - private:
40.59 - Vector<unsigned> offsets_;
40.60 - unsigned size_;
40.61 -};
40.62 -
40.63 -// Represents a property descriptor for a structure field.
40.64 -class Descriptor : public Object
40.65 -{
40.66 - public:
40.67 - enum Visibility {
40.68 - Private,
40.69 - Protected,
40.70 - Public
40.71 - };
40.72 -
40.73 - private:
40.74 - // The name of the field.
40.75 - Barriered<String> name_;
40.76 -
40.77 - // The type of the field.
40.78 - Barriered<Type> type_;
40.79 -
40.80 - // The offset into an object at which this field can be accessed.
40.81 - unsigned offset_;
40.82 -
40.83 - Visibility visibility_;
40.84 -
40.85 - public:
40.86 - static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility);
40.87 -
40.88 - String *name() {
40.89 - return name_;
40.90 - }
40.91 - Type *type() {
40.92 - return type_;
40.93 - }
40.94 - unsigned offset() {
40.95 - assert(offset_ != unsigned(-1));
40.96 - return offset_;
40.97 - }
40.98 - void setOffset(unsigned offset) {
40.99 - assert(offset_ == unsigned(-1));
40.100 - offset_ = offset;
40.101 - }
40.102 -
40.103 - // Begin GC descriptor.
40.104 - static inline size_t offsetOfName() {
40.105 - return OFFSETOF(Descriptor, name_);
40.106 - }
40.107 - static inline size_t offsetOfType() {
40.108 - return OFFSETOF(Descriptor, type_);
40.109 - }
40.110 - // End GC descriptor.
40.111 -
40.112 - static inline Descriptor *cast(Object *obj) {
40.113 - assert(!obj || obj->is(MapKind_Descriptor));
40.114 - return reinterpret_cast<Descriptor *>(obj);
40.115 - }
40.116 -};
40.117 -
40.118 -class StructMap : public Map
40.119 -{
40.120 - unsigned structureSize_;
40.121 - unsigned traceOffsetCount_;
40.122 - Barriered<StructType> type_;
40.123 -
40.124 - // List of descriptors which must be allocated upon initialization.
40.125 - Barriered<FixedArray> composed_;
40.126 -
40.127 - public:
40.128 - static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type);
40.129 -
40.130 - unsigned structureSize() {
40.131 - return structureSize_;
40.132 - }
40.133 - unsigned traceOffsetCount() {
40.134 - return traceOffsetCount_;
40.135 - }
40.136 - const unsigned *traceOffsets() {
40.137 - return reinterpret_cast<unsigned *>(this + 1);
40.138 - }
40.139 - size_t objSize() {
40.140 - return sizeof(StructMap) + sizeof(unsigned) * traceOffsetCount();
40.141 - }
40.142 - StructType *type() {
40.143 - return type_;
40.144 - }
40.145 - FixedArray *composed() {
40.146 - return composed_;
40.147 - }
40.148 -
40.149 - void setType(StructType *type) {
40.150 - assert(!type_);
40.151 - type_ = type;
40.152 - }
40.153 -
40.154 - // Begin GC descriptors.
40.155 - static inline size_t offsetOfType() {
40.156 - return OFFSETOF(StructMap, type_);
40.157 - }
40.158 - static inline size_t offsetOfComposed() {
40.159 - return OFFSETOF(StructMap, composed_);
40.160 - }
40.161 - // End GC descriptors.
40.162 -
40.163 - static inline StructMap *cast(Object *obj) {
40.164 - assert(!obj || obj->is(MapKind_MetaStruct));
40.165 - return reinterpret_cast<StructMap *>(obj);
40.166 - }
40.167 -};
40.168 -
40.169 -class Struct : public Object
40.170 -{
40.171 - public:
40.172 - static Struct *New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
40.173 -
40.174 - static bool Copy(Zone *zone, Handle<Struct> dest, Handle<Struct> src);
40.175 -
40.176 - StructMap *map() {
40.177 - return StructMap::cast(Object::map());
40.178 - }
40.179 -
40.180 - void *ref(Descriptor *desc) {
40.181 - return reinterpret_cast<Address>(this) + offsetOfSlotOffset(desc->offset());
40.182 - }
40.183 -
40.184 - static inline size_t SizeFor(StructMap *map) {
40.185 - return Max(sizeof(Struct) + map->structureSize(), kMinObjectSize);
40.186 - }
40.187 -
40.188 - template <typename T> T get(Descriptor *desc) {
40.189 - return *reinterpret_cast<T *>(ref(desc));
40.190 - }
40.191 -
40.192 - // This must NOT be used with any Object * type!
40.193 - // :TODO: prevent with type system
40.194 - template <typename T> void set(Descriptor *desc, const T &t) {
40.195 - *reinterpret_cast<T *>(ref(desc)) = t;
40.196 - }
40.197 -
40.198 - void set(Zone *zone, Descriptor *desc, Object *obj) {
40.199 - // :TODO: write barrier
40.200 - *reinterpret_cast<Object **>(
40.201 - reinterpret_cast<Address>(this) +
40.202 - offsetOfSlotOffset(desc->offset())) = obj;
40.203 - }
40.204 -
40.205 - static inline size_t offsetOfSlotOffset(unsigned offset) {
40.206 - return sizeof(Struct) + offset;
40.207 - }
40.208 -
40.209 - static inline Struct *cast(Object *obj) {
40.210 - assert(!obj || obj->is(MapKind_Struct));
40.211 - return reinterpret_cast<Struct *>(obj);
40.212 - }
40.213 -};
40.214 -
40.215 -}
40.216 -
40.217 -#endif // _include_jc_structure_h_
40.218 -
40.219 +/* vim: set ts=4 sw=4 tw=99 et:
40.220 + *
40.221 + * Copyright (C) 2012 David Anderson
40.222 + *
40.223 + * This file is part of SourcePawn.
40.224 + *
40.225 + * SourcePawn is free software: you can redistribute it and/or modify it under
40.226 + * the terms of the GNU General Public License as published by the Free
40.227 + * Software Foundation, either version 3 of the License, or (at your option)
40.228 + * any later version.
40.229 + *
40.230 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
40.231 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
40.232 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
40.233 + *
40.234 + * You should have received a copy of the GNU General Public License along with
40.235 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
40.236 + */
40.237 +#ifndef _include_jc_structure_h_
40.238 +#define _include_jc_structure_h_
40.239 +
40.240 +#include "Objects.h"
40.241 +#include "Handles.h"
40.242 +#include "Vector.h"
40.243 +#include "Heap.h"
40.244 +
40.245 +namespace ke {
40.246 +
40.247 +class Type;
40.248 +class String;
40.249 +class FixedArray;
40.250 +class StructType;
40.251 +
40.252 +// When describing composite structures, the GC must be able to trace interior
40.253 +// references to Objects. To make this possible, maps that describe composite
40.254 +// structures must provide a list of offsets into their objects that are
40.255 +// traceable. StructureBufferBuilder assists with this.
40.256 +class StructureBufferBuilder
40.257 +{
40.258 + public:
40.259 + StructureBufferBuilder();
40.260 +
40.261 + bool add(Handle<Type> type, unsigned *offset);
40.262 +
40.263 + unsigned structureSize() const {
40.264 + return size_;
40.265 + }
40.266 + unsigned traceableOffsetCount() const {
40.267 + return offsets_.length();
40.268 + }
40.269 + const unsigned *offsets() const {
40.270 + return offsets_.buffer();
40.271 + }
40.272 +
40.273 + private:
40.274 + Vector<unsigned> offsets_;
40.275 + unsigned size_;
40.276 +};
40.277 +
40.278 +// Represents a property descriptor for a structure field.
40.279 +class Descriptor : public Object
40.280 +{
40.281 + public:
40.282 + enum Visibility {
40.283 + Private,
40.284 + Protected,
40.285 + Public
40.286 + };
40.287 +
40.288 + private:
40.289 + // The name of the field.
40.290 + Barriered<String> name_;
40.291 +
40.292 + // The type of the field.
40.293 + Barriered<Type> type_;
40.294 +
40.295 + // The offset into an object at which this field can be accessed.
40.296 + unsigned offset_;
40.297 +
40.298 + Visibility visibility_;
40.299 +
40.300 + public:
40.301 + static Descriptor *New(Zone *zone, Handle<String> name, Handle<Type> type, Visibility visibility);
40.302 +
40.303 + String *name() {
40.304 + return name_;
40.305 + }
40.306 + Type *type() {
40.307 + return type_;
40.308 + }
40.309 + unsigned offset() {
40.310 + assert(offset_ != unsigned(-1));
40.311 + return offset_;
40.312 + }
40.313 + void setOffset(unsigned offset) {
40.314 + assert(offset_ == unsigned(-1));
40.315 + offset_ = offset;
40.316 + }
40.317 +
40.318 + // Begin GC descriptor.
40.319 + static inline size_t offsetOfName() {
40.320 + return OFFSETOF(Descriptor, name_);
40.321 + }
40.322 + static inline size_t offsetOfType() {
40.323 + return OFFSETOF(Descriptor, type_);
40.324 + }
40.325 + // End GC descriptor.
40.326 +
40.327 + static inline Descriptor *cast(Object *obj) {
40.328 + assert(!obj || obj->is(MapKind_Descriptor));
40.329 + return reinterpret_cast<Descriptor *>(obj);
40.330 + }
40.331 +};
40.332 +
40.333 +class StructMap : public Map
40.334 +{
40.335 + unsigned structureSize_;
40.336 + unsigned traceOffsetCount_;
40.337 + Barriered<StructType> type_;
40.338 +
40.339 + // List of descriptors which must be allocated upon initialization.
40.340 + Barriered<FixedArray> composed_;
40.341 +
40.342 + public:
40.343 + static StructMap *New(Zone *zone, const StructureBufferBuilder &builder, Handle<StructType> type);
40.344 +
40.345 + unsigned structureSize() {
40.346 + return structureSize_;
40.347 + }
40.348 + unsigned traceOffsetCount() {
40.349 + return traceOffsetCount_;
40.350 + }
40.351 + const unsigned *traceOffsets() {
40.352 + return reinterpret_cast<unsigned *>(this + 1);
40.353 + }
40.354 + size_t objSize() {
40.355 + return sizeof(StructMap) + sizeof(unsigned) * traceOffsetCount();
40.356 + }
40.357 + StructType *type() {
40.358 + return type_;
40.359 + }
40.360 + FixedArray *composed() {
40.361 + return composed_;
40.362 + }
40.363 +
40.364 + void setType(StructType *type) {
40.365 + assert(!type_);
40.366 + type_ = type;
40.367 + }
40.368 +
40.369 + // Begin GC descriptors.
40.370 + static inline size_t offsetOfType() {
40.371 + return OFFSETOF(StructMap, type_);
40.372 + }
40.373 + static inline size_t offsetOfComposed() {
40.374 + return OFFSETOF(StructMap, composed_);
40.375 + }
40.376 + // End GC descriptors.
40.377 +
40.378 + static inline StructMap *cast(Object *obj) {
40.379 + assert(!obj || obj->is(MapKind_MetaStruct));
40.380 + return reinterpret_cast<StructMap *>(obj);
40.381 + }
40.382 +};
40.383 +
40.384 +class Struct : public Object
40.385 +{
40.386 + public:
40.387 + static Struct *New(Zone *zone, Handle<StructMap> map, Heap::Tenure tenure = Heap::Tenure_Default);
40.388 +
40.389 + static bool Copy(Zone *zone, Handle<Struct> dest, Handle<Struct> src);
40.390 +
40.391 + StructMap *map() {
40.392 + return StructMap::cast(Object::map());
40.393 + }
40.394 +
40.395 + void *ref(Descriptor *desc) {
40.396 + return reinterpret_cast<Address>(this) + offsetOfSlotOffset(desc->offset());
40.397 + }
40.398 +
40.399 + static inline size_t SizeFor(StructMap *map) {
40.400 + return Max(sizeof(Struct) + map->structureSize(), kMinObjectSize);
40.401 + }
40.402 +
40.403 + template <typename T> T get(Descriptor *desc) {
40.404 + return *reinterpret_cast<T *>(ref(desc));
40.405 + }
40.406 +
40.407 + // This must NOT be used with any Object * type!
40.408 + // :TODO: prevent with type system
40.409 + template <typename T> void set(Descriptor *desc, const T &t) {
40.410 + *reinterpret_cast<T *>(ref(desc)) = t;
40.411 + }
40.412 +
40.413 + void set(Zone *zone, Descriptor *desc, Object *obj) {
40.414 + // :TODO: write barrier
40.415 + *reinterpret_cast<Object **>(
40.416 + reinterpret_cast<Address>(this) +
40.417 + offsetOfSlotOffset(desc->offset())) = obj;
40.418 + }
40.419 +
40.420 + static inline size_t offsetOfSlotOffset(unsigned offset) {
40.421 + return sizeof(Struct) + offset;
40.422 + }
40.423 +
40.424 + static inline Struct *cast(Object *obj) {
40.425 + assert(!obj || obj->is(MapKind_Struct));
40.426 + return reinterpret_cast<Struct *>(obj);
40.427 + }
40.428 +};
40.429 +
40.430 +}
40.431 +
40.432 +#endif // _include_jc_structure_h_
40.433 +
41.1 --- a/src/TypeManager.cpp Mon Jun 10 00:46:29 2013 +0100
41.2 +++ b/src/TypeManager.cpp Mon Jun 10 01:04:43 2013 +0100
41.3 @@ -1,167 +1,167 @@
41.4 -/* vim: set ts=4 sw=4 tw=99 et:
41.5 - *
41.6 - * Copyright (C) 2012 David Anderson
41.7 - *
41.8 - * This file is part of SourcePawn.
41.9 - *
41.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
41.11 - * the terms of the GNU General Public License as published by the Free
41.12 - * Software Foundation, either version 3 of the License, or (at your option)
41.13 - * any later version.
41.14 - *
41.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
41.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
41.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
41.18 - *
41.19 - * You should have received a copy of the GNU General Public License along with
41.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
41.21 - */
41.22 -#include <string.h>
41.23 -#include "Types.h"
41.24 -#include "TypeManager.h"
41.25 -#include "Zone.h"
41.26 -#include "Strings.h"
41.27 -#include "Spaces-inl.h"
41.28 -#include "Heap-inl.h"
41.29 -
41.30 -using namespace ke;
41.31 -
41.32 -
41.33 -TypeManager::TypeManager(Zone *zone)
41.34 - : zone_(zone),
41.35 - qualTable_(ZoneAllocatorPolicy())
41.36 -{
41.37 -}
41.38 -
41.39 -bool
41.40 -TypeManager::initialize()
41.41 -{
41.42 - voidType_ = Type::NewVoid(zone_);
41.43 - if (!voidType_)
41.44 - return false;
41.45 -
41.46 - uncheckedType_ = Type::NewUnchecked(zone_);
41.47 - if (!uncheckedType_)
41.48 - return false;
41.49 -
41.50 - stringType_ = Type::NewString(zone_);
41.51 - if (!stringType_)
41.52 - return false;
41.53 -
41.54 - importableType_ = Type::NewImportable(zone_);
41.55 - if (!importableType_)
41.56 - return false;
41.57 -
41.58 - typeType_ = Type::NewType(zone_);
41.59 - if (!typeType_)
41.60 - return false;
41.61 -
41.62 - if ((primitiveTypes_[PrimitiveType_Int32] = Type::NewPrimitive(zone_, PrimitiveType_Int32)) == NULL)
41.63 - return false;
41.64 - if ((primitiveTypes_[PrimitiveType_Float] = Type::NewPrimitive(zone_, PrimitiveType_Float)) == NULL)
41.65 - return false;
41.66 - if ((primitiveTypes_[PrimitiveType_Native] = Type::NewPrimitive(zone_, PrimitiveType_Native)) == NULL)
41.67 - return false;
41.68 - if ((primitiveTypes_[PrimitiveType_Char] = Type::NewPrimitive(zone_, PrimitiveType_Char)) == NULL)
41.69 - return false;
41.70 - if ((primitiveTypes_[PrimitiveType_Bool] = Type::NewPrimitive(zone_, PrimitiveType_Bool)) == NULL)
41.71 - return false;
41.72 -
41.73 - Local<Type> type(zone_);
41.74 - for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
41.75 - type = primitiveTypes_[i];
41.76 - if ((referenceTypes_[i] = ReferenceType::New(zone_, type)) == NULL)
41.77 - return false;
41.78 - }
41.79 -
41.80 - if (!qualTable_.init(32))
41.81 - return false;
41.82 -
41.83 - return true;
41.84 -}
41.85 -
41.86 -ArrayType *
41.87 -TypeManager::newArray(Handle<Type> contained, int elements)
41.88 -{
41.89 - // :TODO: cache this.
41.90 - return ArrayType::New(zone_, contained, elements);
41.91 -}
41.92 -
41.93 -ArrayType *
41.94 -TypeManager::newExternalArray(Handle<Type> contained)
41.95 -{
41.96 - return ArrayType::NewExternal(zone_, contained);
41.97 -}
41.98 -
41.99 -ReferenceType *
41.100 -TypeManager::getReference(Handle<Type> type, bool isConst)
41.101 -{
41.102 - if (!isConst && type->isPrimitive())
41.103 - return referenceTypes_[type->primitive()];
41.104 -
41.105 - // :TODO: cache this.
41.106 - return ReferenceType::New(zone_, type);
41.107 -}
41.108 -
41.109 -EnumType *
41.110 -TypeManager::newEnum(Handle<String> name)
41.111 -{
41.112 - return EnumType::New(zone_, name);
41.113 -}
41.114 -
41.115 -Type *
41.116 -TypeManager::qualify(Handle<Type> argType, TypeQualifiers quals)
41.117 -{
41.118 - Local<Type> type(zone_, argType->unqualified());
41.119 -
41.120 - if (!quals)
41.121 - return type;
41.122 -
41.123 - LookupKey key(type, quals);
41.124 -
41.125 - // We can't use findForAdd because a GC could rehash the table.
41.126 - TypeHashTable::Result r = qualTable_.find(key);
41.127 - if (r.found())
41.128 - return *r;
41.129 -
41.130 - Type *quald = Type::NewQualified(zone_, quals, type);
41.131 - if (!quald)
41.132 - return NULL;
41.133 -
41.134 - // :TODO: assert-no-gc
41.135 - TypeHashTable::Insert i = qualTable_.findForAdd(key);
41.136 - assert(!i.found());
41.137 -
41.138 - if (!qualTable_.add(i, quald))
41.139 - return NULL;
41.140 -
41.141 - return quald;
41.142 -}
41.143 -
41.144 -void
41.145 -TypeManager::accept(VirtualObjectVisitor *visitor)
41.146 -{
41.147 - visitor->visit(voidType_.address());
41.148 - visitor->visit(uncheckedType_.address());
41.149 - visitor->visit(stringType_.address());
41.150 - visitor->visit(importableType_.address());
41.151 - visitor->visit(typeType_.address());
41.152 - for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
41.153 - visitor->visit(primitiveTypes_[i].address());
41.154 - visitor->visit(referenceTypes_[i].address());
41.155 - }
41.156 -}
41.157 -
41.158 -void
41.159 -TypeManager::sweep()
41.160 -{
41.161 - for (TypeHashTable::iterator i(&qualTable_); !i.empty(); i.next()) {
41.162 - Type *obj = *i;
41.163 - MarkBit bits = HeapChunk::GetMarkBit(obj);
41.164 - if (HeapChunk::IsWhite(bits))
41.165 - i.erase();
41.166 - else
41.167 - assert(HeapChunk::IsBlack(bits));
41.168 - }
41.169 - qualTable_.checkDensity();
41.170 -}
41.171 +/* vim: set ts=4 sw=4 tw=99 et:
41.172 + *
41.173 + * Copyright (C) 2012 David Anderson
41.174 + *
41.175 + * This file is part of SourcePawn.
41.176 + *
41.177 + * SourcePawn is free software: you can redistribute it and/or modify it under
41.178 + * the terms of the GNU General Public License as published by the Free
41.179 + * Software Foundation, either version 3 of the License, or (at your option)
41.180 + * any later version.
41.181 + *
41.182 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
41.183 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
41.184 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
41.185 + *
41.186 + * You should have received a copy of the GNU General Public License along with
41.187 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
41.188 + */
41.189 +#include <string.h>
41.190 +#include "Types.h"
41.191 +#include "TypeManager.h"
41.192 +#include "Zone.h"
41.193 +#include "Strings.h"
41.194 +#include "Spaces-inl.h"
41.195 +#include "Heap-inl.h"
41.196 +
41.197 +using namespace ke;
41.198 +
41.199 +
41.200 +TypeManager::TypeManager(Zone *zone)
41.201 + : zone_(zone),
41.202 + qualTable_(ZoneAllocatorPolicy())
41.203 +{
41.204 +}
41.205 +
41.206 +bool
41.207 +TypeManager::initialize()
41.208 +{
41.209 + voidType_ = Type::NewVoid(zone_);
41.210 + if (!voidType_)
41.211 + return false;
41.212 +
41.213 + uncheckedType_ = Type::NewUnchecked(zone_);
41.214 + if (!uncheckedType_)
41.215 + return false;
41.216 +
41.217 + stringType_ = Type::NewString(zone_);
41.218 + if (!stringType_)
41.219 + return false;
41.220 +
41.221 + importableType_ = Type::NewImportable(zone_);
41.222 + if (!importableType_)
41.223 + return false;
41.224 +
41.225 + typeType_ = Type::NewType(zone_);
41.226 + if (!typeType_)
41.227 + return false;
41.228 +
41.229 + if ((primitiveTypes_[PrimitiveType_Int32] = Type::NewPrimitive(zone_, PrimitiveType_Int32)) == NULL)
41.230 + return false;
41.231 + if ((primitiveTypes_[PrimitiveType_Float] = Type::NewPrimitive(zone_, PrimitiveType_Float)) == NULL)
41.232 + return false;
41.233 + if ((primitiveTypes_[PrimitiveType_Native] = Type::NewPrimitive(zone_, PrimitiveType_Native)) == NULL)
41.234 + return false;
41.235 + if ((primitiveTypes_[PrimitiveType_Char] = Type::NewPrimitive(zone_, PrimitiveType_Char)) == NULL)
41.236 + return false;
41.237 + if ((primitiveTypes_[PrimitiveType_Bool] = Type::NewPrimitive(zone_, PrimitiveType_Bool)) == NULL)
41.238 + return false;
41.239 +
41.240 + Local<Type> type(zone_);
41.241 + for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
41.242 + type = primitiveTypes_[i];
41.243 + if ((referenceTypes_[i] = ReferenceType::New(zone_, type)) == NULL)
41.244 + return false;
41.245 + }
41.246 +
41.247 + if (!qualTable_.init(32))
41.248 + return false;
41.249 +
41.250 + return true;
41.251 +}
41.252 +
41.253 +ArrayType *
41.254 +TypeManager::newArray(Handle<Type> contained, int elements)
41.255 +{
41.256 + // :TODO: cache this.
41.257 + return ArrayType::New(zone_, contained, elements);
41.258 +}
41.259 +
41.260 +ArrayType *
41.261 +TypeManager::newExternalArray(Handle<Type> contained)
41.262 +{
41.263 + return ArrayType::NewExternal(zone_, contained);
41.264 +}
41.265 +
41.266 +ReferenceType *
41.267 +TypeManager::getReference(Handle<Type> type, bool isConst)
41.268 +{
41.269 + if (!isConst && type->isPrimitive())
41.270 + return referenceTypes_[type->primitive()];
41.271 +
41.272 + // :TODO: cache this.
41.273 + return ReferenceType::New(zone_, type);
41.274 +}
41.275 +
41.276 +EnumType *
41.277 +TypeManager::newEnum(Handle<String> name)
41.278 +{
41.279 + return EnumType::New(zone_, name);
41.280 +}
41.281 +
41.282 +Type *
41.283 +TypeManager::qualify(Handle<Type> argType, TypeQualifiers quals)
41.284 +{
41.285 + Local<Type> type(zone_, argType->unqualified());
41.286 +
41.287 + if (!quals)
41.288 + return type;
41.289 +
41.290 + LookupKey key(type, quals);
41.291 +
41.292 + // We can't use findForAdd because a GC could rehash the table.
41.293 + TypeHashTable::Result r = qualTable_.find(key);
41.294 + if (r.found())
41.295 + return *r;
41.296 +
41.297 + Type *quald = Type::NewQualified(zone_, quals, type);
41.298 + if (!quald)
41.299 + return NULL;
41.300 +
41.301 + // :TODO: assert-no-gc
41.302 + TypeHashTable::Insert i = qualTable_.findForAdd(key);
41.303 + assert(!i.found());
41.304 +
41.305 + if (!qualTable_.add(i, quald))
41.306 + return NULL;
41.307 +
41.308 + return quald;
41.309 +}
41.310 +
41.311 +void
41.312 +TypeManager::accept(VirtualObjectVisitor *visitor)
41.313 +{
41.314 + visitor->visit(voidType_.address());
41.315 + visitor->visit(uncheckedType_.address());
41.316 + visitor->visit(stringType_.address());
41.317 + visitor->visit(importableType_.address());
41.318 + visitor->visit(typeType_.address());
41.319 + for (unsigned i = 0; i < PrimitiveTypes_Total; i++) {
41.320 + visitor->visit(primitiveTypes_[i].address());
41.321 + visitor->visit(referenceTypes_[i].address());
41.322 + }
41.323 +}
41.324 +
41.325 +void
41.326 +TypeManager::sweep()
41.327 +{
41.328 + for (TypeHashTable::iterator i(&qualTable_); !i.empty(); i.next()) {
41.329 + Type *obj = *i;
41.330 + MarkBit bits = HeapChunk::GetMarkBit(obj);
41.331 + if (HeapChunk::IsWhite(bits))
41.332 + i.erase();
41.333 + else
41.334 + assert(HeapChunk::IsBlack(bits));
41.335 + }
41.336 + qualTable_.checkDensity();
41.337 +}
42.1 --- a/src/TypeManager.h Mon Jun 10 00:46:29 2013 +0100
42.2 +++ b/src/TypeManager.h Mon Jun 10 01:04:43 2013 +0100
42.3 @@ -1,115 +1,115 @@
42.4 -/* vim: set ts=4 sw=4 tw=99 et:
42.5 - *
42.6 - * Copyright (C) 2012 David Anderson
42.7 - *
42.8 - * This file is part of SourcePawn.
42.9 - *
42.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
42.11 - * the terms of the GNU General Public License as published by the Free
42.12 - * Software Foundation, either version 3 of the License, or (at your option)
42.13 - * any later version.
42.14 - *
42.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
42.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
42.18 - *
42.19 - * You should have received a copy of the GNU General Public License along with
42.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
42.21 - */
42.22 -#ifndef _include_jitcraft_type_manager_h_
42.23 -#define _include_jitcraft_type_manager_h_
42.24 -
42.25 -#include "Barriers.h"
42.26 -#include "Types.h"
42.27 -#include "HashTable.h"
42.28 -#include "AllocatorPolicies.h"
42.29 -#include "VirtualObjectVisitor.h"
42.30 -
42.31 -namespace ke {
42.32 -
42.33 -class String;
42.34 -
42.35 -class TypeManager
42.36 -{
42.37 - struct LookupKey
42.38 - {
42.39 - Handle<Type> type;
42.40 - TypeQualifiers quals;
42.41 -
42.42 - LookupKey(Handle<Type> type, TypeQualifiers quals)
42.43 - : type(type),
42.44 - quals(quals)
42.45 - {
42.46 - }
42.47 - };
42.48 -
42.49 - struct Policy
42.50 - {
42.51 - typedef Type * Payload;
42.52 -
42.53 - static uint32 hash(const LookupKey &key) {
42.54 - // We'll need to rehash with moving GC.
42.55 - return HashPointer(key.type);
42.56 - }
42.57 -
42.58 - static bool matches(const LookupKey &key, Type *type) {
42.59 - assert(type->hasTypeQualifiers());
42.60 - return key.type == type->unqualified() &&
42.61 - key.quals == type->quals();
42.62 - }
42.63 - };
42.64 -
42.65 - typedef HashTable<Policy, ZoneAllocatorPolicy> TypeHashTable;
42.66 -
42.67 - public:
42.68 - TypeManager(Zone *zone);
42.69 -
42.70 - bool initialize();
42.71 -
42.72 - Type *getPrimitive(PrimitiveType type) {
42.73 - return primitiveTypes_[type];
42.74 - }
42.75 -
42.76 - Type *getString() {
42.77 - return stringType_;
42.78 - }
42.79 - Type *getVoid() {
42.80 - return voidType_;
42.81 - }
42.82 - Type *getUnchecked() {
42.83 - return uncheckedType_;
42.84 - }
42.85 - Type *getImportable() {
42.86 - return importableType_;
42.87 - }
42.88 - Type *getType() {
42.89 - return typeType_;
42.90 - }
42.91 - ReferenceType *getReference(Handle<Type> type, bool isConst);
42.92 - ArrayType *newArray(Handle<Type> contained, int elements);
42.93 - ArrayType *newExternalArray(Handle<Type> contained);
42.94 - EnumType *newEnum(Handle<String> name);
42.95 -
42.96 - void accept(VirtualObjectVisitor *visitor);
42.97 - void sweep();
42.98 -
42.99 - Type *qualify(Handle<Type> type, TypeQualifiers quals);
42.100 -
42.101 - private:
42.102 - Zone *zone_;
42.103 -
42.104 - // Primitive type cache.
42.105 - Unbarriered<Type> voidType_;
42.106 - Unbarriered<Type> stringType_;
42.107 - Unbarriered<Type> uncheckedType_;
42.108 - Unbarriered<Type> importableType_;
42.109 - Unbarriered<Type> typeType_;
42.110 - Unbarriered<Type> primitiveTypes_[PrimitiveTypes_Total];
42.111 - Unbarriered<ReferenceType> referenceTypes_[PrimitiveTypes_Total];
42.112 -
42.113 - TypeHashTable qualTable_;
42.114 -};
42.115 -
42.116 -}
42.117 -
42.118 -#endif // _include_jitcraft_type_manager_h_
42.119 +/* vim: set ts=4 sw=4 tw=99 et:
42.120 + *
42.121 + * Copyright (C) 2012 David Anderson
42.122 + *
42.123 + * This file is part of SourcePawn.
42.124 + *
42.125 + * SourcePawn is free software: you can redistribute it and/or modify it under
42.126 + * the terms of the GNU General Public License as published by the Free
42.127 + * Software Foundation, either version 3 of the License, or (at your option)
42.128 + * any later version.
42.129 + *
42.130 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
42.131 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42.132 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
42.133 + *
42.134 + * You should have received a copy of the GNU General Public License along with
42.135 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
42.136 + */
42.137 +#ifndef _include_jitcraft_type_manager_h_
42.138 +#define _include_jitcraft_type_manager_h_
42.139 +
42.140 +#include "Barriers.h"
42.141 +#include "Types.h"
42.142 +#include "HashTable.h"
42.143 +#include "AllocatorPolicies.h"
42.144 +#include "VirtualObjectVisitor.h"
42.145 +
42.146 +namespace ke {
42.147 +
42.148 +class String;
42.149 +
42.150 +class TypeManager
42.151 +{
42.152 + struct LookupKey
42.153 + {
42.154 + Handle<Type> type;
42.155 + TypeQualifiers quals;
42.156 +
42.157 + LookupKey(Handle<Type> type, TypeQualifiers quals)
42.158 + : type(type),
42.159 + quals(quals)
42.160 + {
42.161 + }
42.162 + };
42.163 +
42.164 + struct Policy
42.165 + {
42.166 + typedef Type * Payload;
42.167 +
42.168 + static uint32 hash(const LookupKey &key) {
42.169 + // We'll need to rehash with moving GC.
42.170 + return HashPointer(key.type);
42.171 + }
42.172 +
42.173 + static bool matches(const LookupKey &key, Type *type) {
42.174 + assert(type->hasTypeQualifiers());
42.175 + return key.type == type->unqualified() &&
42.176 + key.quals == type->quals();
42.177 + }
42.178 + };
42.179 +
42.180 + typedef HashTable<Policy, ZoneAllocatorPolicy> TypeHashTable;
42.181 +
42.182 + public:
42.183 + TypeManager(Zone *zone);
42.184 +
42.185 + bool initialize();
42.186 +
42.187 + Type *getPrimitive(PrimitiveType type) {
42.188 + return primitiveTypes_[type];
42.189 + }
42.190 +
42.191 + Type *getString() {
42.192 + return stringType_;
42.193 + }
42.194 + Type *getVoid() {
42.195 + return voidType_;
42.196 + }
42.197 + Type *getUnchecked() {
42.198 + return uncheckedType_;
42.199 + }
42.200 + Type *getImportable() {
42.201 + return importableType_;
42.202 + }
42.203 + Type *getType() {
42.204 + return typeType_;
42.205 + }
42.206 + ReferenceType *getReference(Handle<Type> type, bool isConst);
42.207 + ArrayType *newArray(Handle<Type> contained, int elements);
42.208 + ArrayType *newExternalArray(Handle<Type> contained);
42.209 + EnumType *newEnum(Handle<String> name);
42.210 +
42.211 + void accept(VirtualObjectVisitor *visitor);
42.212 + void sweep();
42.213 +
42.214 + Type *qualify(Handle<Type> type, TypeQualifiers quals);
42.215 +
42.216 + private:
42.217 + Zone *zone_;
42.218 +
42.219 + // Primitive type cache.
42.220 + Unbarriered<Type> voidType_;
42.221 + Unbarriered<Type> stringType_;
42.222 + Unbarriered<Type> uncheckedType_;
42.223 + Unbarriered<Type> importableType_;
42.224 + Unbarriered<Type> typeType_;
42.225 + Unbarriered<Type> primitiveTypes_[PrimitiveTypes_Total];
42.226 + Unbarriered<ReferenceType> referenceTypes_[PrimitiveTypes_Total];
42.227 +
42.228 + TypeHashTable qualTable_;
42.229 +};
42.230 +
42.231 +}
42.232 +
42.233 +#endif // _include_jitcraft_type_manager_h_
43.1 --- a/src/Types.cpp Mon Jun 10 00:46:29 2013 +0100
43.2 +++ b/src/Types.cpp Mon Jun 10 01:04:43 2013 +0100
43.3 @@ -1,333 +1,333 @@
43.4 -/* vim: set ts=4 sw=4 tw=99 et:
43.5 - *
43.6 - * Copyright (C) 2012 David Anderson
43.7 - *
43.8 - * This file is part of SourcePawn.
43.9 - *
43.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
43.11 - * the terms of the GNU General Public License as published by the Free
43.12 - * Software Foundation, either version 3 of the License, or (at your option)
43.13 - * any later version.
43.14 - *
43.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
43.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
43.18 - *
43.19 - * You should have received a copy of the GNU General Public License along with
43.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
43.21 - */
43.22 -#include <string.h>
43.23 -#include "Types.h"
43.24 -#include "Zone.h"
43.25 -#include "Strings.h"
43.26 -#include "Array.h"
43.27 -#include "Structures.h"
43.28 -#include "Heap-inl.h"
43.29 -
43.30 -using namespace ke;
43.31 -
43.32 -void
43.33 -Type::init(Kind kind, Type *root)
43.34 -{
43.35 - this->kind_ = kind;
43.36 - this->root_ = root ? root : this;
43.37 -}
43.38 -
43.39 -Type *
43.40 -Type::NewVoid(Zone *zone)
43.41 -{
43.42 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.43 - if (!type)
43.44 - return NULL;
43.45 -
43.46 - type->init(VOID);
43.47 - return type;
43.48 -}
43.49 -
43.50 -Type *
43.51 -Type::NewImportable(Zone *zone)
43.52 -{
43.53 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.54 - if (!type)
43.55 - return NULL;
43.56 -
43.57 - type->init(IMPORTABLE);
43.58 - return type;
43.59 -}
43.60 -
43.61 -Type *
43.62 -Type::NewString(Zone *zone)
43.63 -{
43.64 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.65 - if (!type)
43.66 - return NULL;
43.67 -
43.68 - type->init(STRING);
43.69 - return type;
43.70 -}
43.71 -
43.72 -Type *
43.73 -Type::NewUnchecked(Zone *zone)
43.74 -{
43.75 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.76 - if (!type)
43.77 - return NULL;
43.78 -
43.79 - type->init(UNCHECKED);
43.80 - return type;
43.81 -}
43.82 -
43.83 -Type *
43.84 -Type::NewType(Zone *zone)
43.85 -{
43.86 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.87 - if (!type)
43.88 - return NULL;
43.89 -
43.90 - type->init(TYPE);
43.91 - return type;
43.92 -}
43.93 -
43.94 -Type *
43.95 -Type::NewPrimitive(Zone *zone, PrimitiveType prim)
43.96 -{
43.97 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.98 - if (!type)
43.99 - return NULL;
43.100 -
43.101 - type->init(PRIMITIVE);
43.102 - type->primitive_ = prim;
43.103 - return type;
43.104 -}
43.105 -
43.106 -Type *
43.107 -Type::NewQualified(Zone *zone, TypeQualifiers qual, Handle<Type> root)
43.108 -{
43.109 - Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.110 - if (!type)
43.111 - return NULL;
43.112 -
43.113 - type->init(QUALTYPE, root);
43.114 - type->quals_ = qual;
43.115 - return type;
43.116 -}
43.117 -
43.118 -ArrayType *
43.119 -ArrayType::New(Zone *zone, Handle<Type> contained, int elements)
43.120 -{
43.121 - if (contained->isArray() &&
43.122 - ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH)
43.123 - {
43.124 - zone->reportError(Message_MaximumArrayDepth);
43.125 - return NULL;
43.126 - }
43.127 -
43.128 - Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
43.129 - if (!type)
43.130 - return NULL;
43.131 -
43.132 - type->init(ARRAY);
43.133 - type->contained_ = contained;
43.134 - type->elements_ = elements;
43.135 - if (!contained->isArray())
43.136 - type->levels_ = 1;
43.137 - else
43.138 - type->levels_ = ArrayType::cast(contained)->levels() + 1;
43.139 -
43.140 - type->newMap_ = ArrayMap::New(zone, type);
43.141 - if (!type->newMap_)
43.142 - return NULL;
43.143 -
43.144 - return type;
43.145 -}
43.146 -
43.147 -ArrayType *
43.148 -ArrayType::NewExternal(Zone *zone, Handle<Type> contained)
43.149 -{
43.150 - Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
43.151 - if (!type)
43.152 - return NULL;
43.153 -
43.154 - assert(contained->isPrimitive());
43.155 -
43.156 - type->init(EXTERNAL_ARRAY);
43.157 - type->contained_ = contained;
43.158 - type->elements_ = DYNAMIC_ARRAY_SIZE;
43.159 - type->levels_ = 1;
43.160 - return type;
43.161 -}
43.162 -
43.163 -ReferenceType *
43.164 -ReferenceType::New(Zone *zone, Handle<Type> contained)
43.165 -{
43.166 - Local<ReferenceType> type(zone, (ReferenceType *)zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old));
43.167 - if (!type)
43.168 - return NULL;
43.169 -
43.170 - type->init(REFERENCE);
43.171 - type->contained_ = contained;
43.172 - return type;
43.173 -}
43.174 -
43.175 -EnumType *
43.176 -EnumType::New(Zone *zone, Handle<String> name)
43.177 -{
43.178 - Local<EnumType> type(zone, (EnumType *)zone->allocate(MapKind_EnumType, sizeof(EnumType), Heap::Tenure_Old));
43.179 - if (!type)
43.180 - return NULL;
43.181 -
43.182 - type->init(ENUM);
43.183 - type->name_ = name;
43.184 - type->fields_ = NULL;
43.185 - return type;
43.186 -}
43.187 -
43.188 -StructType *
43.189 -StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
43.190 -{
43.191 - Local<StructType> type(zone, (StructType *)zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old));
43.192 - if (!type)
43.193 - return NULL;
43.194 -
43.195 - type->init(STRUCT);
43.196 - type->newMap_ = NULL;
43.197 - type->fields_ = fields;
43.198 - type->name_ = name;
43.199 -
43.200 - // Fill in field offsets.
43.201 - StructureBufferBuilder builder;
43.202 - Local<Type> fieldType(zone);
43.203 - for (size_t i = 0; i < fields->length(); i++) {
43.204 - Descriptor *desc = Descriptor::cast(fields->at(i));
43.205 - fieldType = desc->type();
43.206 -
43.207 - unsigned offset;
43.208 - if (!builder.add(fieldType, &offset))
43.209 - return NULL;
43.210 - desc->setOffset(offset);
43.211 - }
43.212 -
43.213 - Local<StructMap> map(zone, StructMap::New(zone, builder, type));
43.214 - if (!map)
43.215 - return NULL;
43.216 -
43.217 - type->newMap_ = map;
43.218 -
43.219 - return type;
43.220 -}
43.221 -
43.222 -Descriptor *
43.223 -StructType::lookupField(String *name, unsigned *index)
43.224 -{
43.225 - // :TODO: assert no GC
43.226 - for (unsigned i = 0; i < fields_->length(); i++) {
43.227 - Descriptor *desc = Descriptor::cast(fields_->at(i));
43.228 - if (desc->name() == name) {
43.229 - if (index)
43.230 - *index = i;
43.231 - return desc;
43.232 - }
43.233 - }
43.234 -
43.235 - return NULL;
43.236 -}
43.237 -
43.238 -FunctionType *
43.239 -FunctionType::New(Zone *zone, Handle<String> name, TokenKind token)
43.240 -{
43.241 - Local<FunctionType> type(zone, (FunctionType *)zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old));
43.242 - if (!type)
43.243 - return NULL;
43.244 -
43.245 - type->init(FUNCTION);
43.246 - type->parameters_ = NULL;
43.247 - type->defaults_ = NULL;
43.248 - type->returnType_ = NULL;
43.249 - type->name_ = name;
43.250 - type->token_ = token;
43.251 - return type;
43.252 -}
43.253 -
43.254 -static size_t
43.255 -FormatVA(char *buffer, size_t maxlen, const char *text, va_list ap)
43.256 -{
43.257 - size_t len = vsnprintf(buffer, maxlen, text, ap);
43.258 - if (len >= maxlen) {
43.259 - buffer[maxlen - 1] = '\0';
43.260 - return maxlen - 1;
43.261 - }
43.262 - return len;
43.263 -}
43.264 -
43.265 -static size_t
43.266 -Format(char *buffer, size_t maxlen, const char *text, ...)
43.267 -{
43.268 - va_list ap;
43.269 - va_start(ap, text);
43.270 - size_t len = FormatVA(buffer, maxlen, text, ap);
43.271 - va_end(ap);
43.272 - return len;
43.273 -}
43.274 -
43.275 -static size_t
43.276 -FormatTypeName(Type *type, char *buffer, size_t maxlen)
43.277 -{
43.278 - if (type->isArray()) {
43.279 - ArrayType *atype = ArrayType::cast(type);
43.280 - Type *innermost = atype->innermost();
43.281 -
43.282 - size_t len = FormatTypeName(innermost, buffer, maxlen);
43.283 - for (;;) {
43.284 - if (atype->isFixedLength())
43.285 - len += Format(buffer + len, maxlen - len, "[%d]", atype->fixedLength());
43.286 - else
43.287 - len += Format(buffer + len, maxlen - len, "[]");
43.288 - if (!atype->contained()->isArray())
43.289 - break;
43.290 - atype = ArrayType::cast(atype->contained());
43.291 - }
43.292 - return len;
43.293 - }
43.294 - if (type->hasTypeQualifiers()) {
43.295 - size_t len = 0;
43.296 - if (type->quals() & TypeQual_Const)
43.297 - len += Format(buffer, maxlen, "const ");
43.298 - return len + FormatTypeName(type->unqualified(), buffer + len, maxlen - len);
43.299 - }
43.300 - if (type->isFunction())
43.301 - return Format(buffer, maxlen, "function");
43.302 - if (type->isVoid())
43.303 - return Format(buffer, maxlen, "void");
43.304 - if (type->isUnchecked())
43.305 - return Format(buffer, maxlen, "unchecked");
43.306 - if (type->isImportable())
43.307 - return Format(buffer, maxlen, "import");
43.308 - if (type->isEnum())
43.309 - return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars());
43.310 - if (type->isStruct())
43.311 - return Format(buffer, maxlen, "%s", StructType::cast(type)->name()->chars());
43.312 - if (type->isReference()) {
43.313 - ReferenceType *ref = ReferenceType::cast(type);
43.314 - size_t len = Format(buffer, maxlen, "&");
43.315 - return len + FormatTypeName(ref->contained(), buffer + len, maxlen - len);
43.316 - }
43.317 - switch (type->primitive()) {
43.318 - case PrimitiveType_Bool:
43.319 - return Format(buffer, maxlen, "bool");
43.320 - case PrimitiveType_Char:
43.321 - return Format(buffer, maxlen, "char");
43.322 - case PrimitiveType_Int32:
43.323 - return Format(buffer, maxlen, "int");
43.324 - case PrimitiveType_Float:
43.325 - return Format(buffer, maxlen, "float");
43.326 - default:
43.327 - return Format(buffer, maxlen, "<UNKNOWN>");
43.328 - }
43.329 -}
43.330 -
43.331 -const char *
43.332 -ke::GetTypeName(Type *type, char *buffer, size_t maxlen)
43.333 -{
43.334 - FormatTypeName(type, buffer, maxlen);
43.335 - return buffer;
43.336 -}
43.337 +/* vim: set ts=4 sw=4 tw=99 et:
43.338 + *
43.339 + * Copyright (C) 2012 David Anderson
43.340 + *
43.341 + * This file is part of SourcePawn.
43.342 + *
43.343 + * SourcePawn is free software: you can redistribute it and/or modify it under
43.344 + * the terms of the GNU General Public License as published by the Free
43.345 + * Software Foundation, either version 3 of the License, or (at your option)
43.346 + * any later version.
43.347 + *
43.348 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
43.349 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43.350 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
43.351 + *
43.352 + * You should have received a copy of the GNU General Public License along with
43.353 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
43.354 + */
43.355 +#include <string.h>
43.356 +#include "Types.h"
43.357 +#include "Zone.h"
43.358 +#include "Strings.h"
43.359 +#include "Array.h"
43.360 +#include "Structures.h"
43.361 +#include "Heap-inl.h"
43.362 +
43.363 +using namespace ke;
43.364 +
43.365 +void
43.366 +Type::init(Kind kind, Type *root)
43.367 +{
43.368 + this->kind_ = kind;
43.369 + this->root_ = root ? root : this;
43.370 +}
43.371 +
43.372 +Type *
43.373 +Type::NewVoid(Zone *zone)
43.374 +{
43.375 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.376 + if (!type)
43.377 + return NULL;
43.378 +
43.379 + type->init(VOID);
43.380 + return type;
43.381 +}
43.382 +
43.383 +Type *
43.384 +Type::NewImportable(Zone *zone)
43.385 +{
43.386 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.387 + if (!type)
43.388 + return NULL;
43.389 +
43.390 + type->init(IMPORTABLE);
43.391 + return type;
43.392 +}
43.393 +
43.394 +Type *
43.395 +Type::NewString(Zone *zone)
43.396 +{
43.397 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.398 + if (!type)
43.399 + return NULL;
43.400 +
43.401 + type->init(STRING);
43.402 + return type;
43.403 +}
43.404 +
43.405 +Type *
43.406 +Type::NewUnchecked(Zone *zone)
43.407 +{
43.408 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.409 + if (!type)
43.410 + return NULL;
43.411 +
43.412 + type->init(UNCHECKED);
43.413 + return type;
43.414 +}
43.415 +
43.416 +Type *
43.417 +Type::NewType(Zone *zone)
43.418 +{
43.419 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.420 + if (!type)
43.421 + return NULL;
43.422 +
43.423 + type->init(TYPE);
43.424 + return type;
43.425 +}
43.426 +
43.427 +Type *
43.428 +Type::NewPrimitive(Zone *zone, PrimitiveType prim)
43.429 +{
43.430 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.431 + if (!type)
43.432 + return NULL;
43.433 +
43.434 + type->init(PRIMITIVE);
43.435 + type->primitive_ = prim;
43.436 + return type;
43.437 +}
43.438 +
43.439 +Type *
43.440 +Type::NewQualified(Zone *zone, TypeQualifiers qual, Handle<Type> root)
43.441 +{
43.442 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
43.443 + if (!type)
43.444 + return NULL;
43.445 +
43.446 + type->init(QUALTYPE, root);
43.447 + type->quals_ = qual;
43.448 + return type;
43.449 +}
43.450 +
43.451 +ArrayType *
43.452 +ArrayType::New(Zone *zone, Handle<Type> contained, int elements)
43.453 +{
43.454 + if (contained->isArray() &&
43.455 + ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH)
43.456 + {
43.457 + zone->reportError(Message_MaximumArrayDepth);
43.458 + return NULL;
43.459 + }
43.460 +
43.461 + Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
43.462 + if (!type)
43.463 + return NULL;
43.464 +
43.465 + type->init(ARRAY);
43.466 + type->contained_ = contained;
43.467 + type->elements_ = elements;
43.468 + if (!contained->isArray())
43.469 + type->levels_ = 1;
43.470 + else
43.471 + type->levels_ = ArrayType::cast(contained)->levels() + 1;
43.472 +
43.473 + type->newMap_ = ArrayMap::New(zone, type);
43.474 + if (!type->newMap_)
43.475 + return NULL;
43.476 +
43.477 + return type;
43.478 +}
43.479 +
43.480 +ArrayType *
43.481 +ArrayType::NewExternal(Zone *zone, Handle<Type> contained)
43.482 +{
43.483 + Local<ArrayType> type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old));
43.484 + if (!type)
43.485 + return NULL;
43.486 +
43.487 + assert(contained->isPrimitive());
43.488 +
43.489 + type->init(EXTERNAL_ARRAY);
43.490 + type->contained_ = contained;
43.491 + type->elements_ = DYNAMIC_ARRAY_SIZE;
43.492 + type->levels_ = 1;
43.493 + return type;
43.494 +}
43.495 +
43.496 +ReferenceType *
43.497 +ReferenceType::New(Zone *zone, Handle<Type> contained)
43.498 +{
43.499 + Local<ReferenceType> type(zone, (ReferenceType *)zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old));
43.500 + if (!type)
43.501 + return NULL;
43.502 +
43.503 + type->init(REFERENCE);
43.504 + type->contained_ = contained;
43.505 + return type;
43.506 +}
43.507 +
43.508 +EnumType *
43.509 +EnumType::New(Zone *zone, Handle<String> name)
43.510 +{
43.511 + Local<EnumType> type(zone, (EnumType *)zone->allocate(MapKind_EnumType, sizeof(EnumType), Heap::Tenure_Old));
43.512 + if (!type)
43.513 + return NULL;
43.514 +
43.515 + type->init(ENUM);
43.516 + type->name_ = name;
43.517 + type->fields_ = NULL;
43.518 + return type;
43.519 +}
43.520 +
43.521 +StructType *
43.522 +StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
43.523 +{
43.524 + Local<StructType> type(zone, (StructType *)zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old));
43.525 + if (!type)
43.526 + return NULL;
43.527 +
43.528 + type->init(STRUCT);
43.529 + type->newMap_ = NULL;
43.530 + type->fields_ = fields;
43.531 + type->name_ = name;
43.532 +
43.533 + // Fill in field offsets.
43.534 + StructureBufferBuilder builder;
43.535 + Local<Type> fieldType(zone);
43.536 + for (size_t i = 0; i < fields->length(); i++) {
43.537 + Descriptor *desc = Descriptor::cast(fields->at(i));
43.538 + fieldType = desc->type();
43.539 +
43.540 + unsigned offset;
43.541 + if (!builder.add(fieldType, &offset))
43.542 + return NULL;
43.543 + desc->setOffset(offset);
43.544 + }
43.545 +
43.546 + Local<StructMap> map(zone, StructMap::New(zone, builder, type));
43.547 + if (!map)
43.548 + return NULL;
43.549 +
43.550 + type->newMap_ = map;
43.551 +
43.552 + return type;
43.553 +}
43.554 +
43.555 +Descriptor *
43.556 +StructType::lookupField(String *name, unsigned *index)
43.557 +{
43.558 + // :TODO: assert no GC
43.559 + for (unsigned i = 0; i < fields_->length(); i++) {
43.560 + Descriptor *desc = Descriptor::cast(fields_->at(i));
43.561 + if (desc->name() == name) {
43.562 + if (index)
43.563 + *index = i;
43.564 + return desc;
43.565 + }
43.566 + }
43.567 +
43.568 + return NULL;
43.569 +}
43.570 +
43.571 +FunctionType *
43.572 +FunctionType::New(Zone *zone, Handle<String> name, TokenKind token)
43.573 +{
43.574 + Local<FunctionType> type(zone, (FunctionType *)zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old));
43.575 + if (!type)
43.576 + return NULL;
43.577 +
43.578 + type->init(FUNCTION);
43.579 + type->parameters_ = NULL;
43.580 + type->defaults_ = NULL;
43.581 + type->returnType_ = NULL;
43.582 + type->name_ = name;
43.583 + type->token_ = token;
43.584 + return type;
43.585 +}
43.586 +
43.587 +static size_t
43.588 +FormatVA(char *buffer, size_t maxlen, const char *text, va_list ap)
43.589 +{
43.590 + size_t len = vsnprintf(buffer, maxlen, text, ap);
43.591 + if (len >= maxlen) {
43.592 + buffer[maxlen - 1] = '\0';
43.593 + return maxlen - 1;
43.594 + }
43.595 + return len;
43.596 +}
43.597 +
43.598 +static size_t
43.599 +Format(char *buffer, size_t maxlen, const char *text, ...)
43.600 +{
43.601 + va_list ap;
43.602 + va_start(ap, text);
43.603 + size_t len = FormatVA(buffer, maxlen, text, ap);
43.604 + va_end(ap);
43.605 + return len;
43.606 +}
43.607 +
43.608 +static size_t
43.609 +FormatTypeName(Type *type, char *buffer, size_t maxlen)
43.610 +{
43.611 + if (type->isArray()) {
43.612 + ArrayType *atype = ArrayType::cast(type);
43.613 + Type *innermost = atype->innermost();
43.614 +
43.615 + size_t len = FormatTypeName(innermost, buffer, maxlen);
43.616 + for (;;) {
43.617 + if (atype->isFixedLength())
43.618 + len += Format(buffer + len, maxlen - len, "[%d]", atype->fixedLength());
43.619 + else
43.620 + len += Format(buffer + len, maxlen - len, "[]");
43.621 + if (!atype->contained()->isArray())
43.622 + break;
43.623 + atype = ArrayType::cast(atype->contained());
43.624 + }
43.625 + return len;
43.626 + }
43.627 + if (type->hasTypeQualifiers()) {
43.628 + size_t len = 0;
43.629 + if (type->quals() & TypeQual_Const)
43.630 + len += Format(buffer, maxlen, "const ");
43.631 + return len + FormatTypeName(type->unqualified(), buffer + len, maxlen - len);
43.632 + }
43.633 + if (type->isFunction())
43.634 + return Format(buffer, maxlen, "function");
43.635 + if (type->isVoid())
43.636 + return Format(buffer, maxlen, "void");
43.637 + if (type->isUnchecked())
43.638 + return Format(buffer, maxlen, "unchecked");
43.639 + if (type->isImportable())
43.640 + return Format(buffer, maxlen, "import");
43.641 + if (type->isEnum())
43.642 + return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars());
43.643 + if (type->isStruct())
43.644 + return Format(buffer, maxlen, "%s", StructType::cast(type)->name()->chars());
43.645 + if (type->isReference()) {
43.646 + ReferenceType *ref = ReferenceType::cast(type);
43.647 + size_t len = Format(buffer, maxlen, "&");
43.648 + return len + FormatTypeName(ref->contained(), buffer + len, maxlen - len);
43.649 + }
43.650 + switch (type->primitive()) {
43.651 + case PrimitiveType_Bool:
43.652 + return Format(buffer, maxlen, "bool");
43.653 + case PrimitiveType_Char:
43.654 + return Format(buffer, maxlen, "char");
43.655 + case PrimitiveType_Int32:
43.656 + return Format(buffer, maxlen, "int");
43.657 + case PrimitiveType_Float:
43.658 + return Format(buffer, maxlen, "float");
43.659 + default:
43.660 + return Format(buffer, maxlen, "<UNKNOWN>");
43.661 + }
43.662 +}
43.663 +
43.664 +const char *
43.665 +ke::GetTypeName(Type *type, char *buffer, size_t maxlen)
43.666 +{
43.667 + FormatTypeName(type, buffer, maxlen);
43.668 + return buffer;
43.669 +}
44.1 --- a/src/Zone.cpp Mon Jun 10 00:46:29 2013 +0100
44.2 +++ b/src/Zone.cpp Mon Jun 10 01:04:43 2013 +0100
44.3 @@ -1,368 +1,368 @@
44.4 -/* vim: set ts=4 sw=4 tw=99 et:
44.5 - *
44.6 - * Copyright (C) 2012 David Anderson
44.7 - *
44.8 - * This file is part of JITCraft.
44.9 - *
44.10 - * JITCraft is free software: you can redistribute it and/or modify it under
44.11 - * the terms of the GNU General Public License as published by the Free
44.12 - * Software Foundation, either version 3 of the License, or (at your option)
44.13 - * any later version.
44.14 - *
44.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
44.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
44.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
44.18 - *
44.19 - * You should have received a copy of the GNU General Public License along with
44.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
44.21 - */
44.22 -#include <stdlib.h>
44.23 -#include "Zone.h"
44.24 -#include "StringPool.h"
44.25 -#include "TypeManager.h"
44.26 -#include "GlobalRoots.h"
44.27 -#include "AllocatorPolicies.h"
44.28 -#include "Array.h"
44.29 -#include "NativeTable.h"
44.30 -#include "Packages.h"
44.31 -#include "Spaces-inl.h"
44.32 -#include "Heap-inl.h"
44.33 -
44.34 -using namespace ke;
44.35 -
44.36 -Zone *ke::SingleThreadedZone;
44.37 -
44.38 -void * const NullAddress::Sentinel = NULL;
44.39 -
44.40 -Zone::Zone()
44.41 - : stack_(thisFromCtor()),
44.42 - heap_(thisFromCtor()),
44.43 - types_(NULL),
44.44 - symbols_(NULL),
44.45 - globalRoots_(NULL),
44.46 - nativeTable_(NULL),
44.47 - packages_(NULL),
44.48 - lastLocalRoot_(NULL),
44.49 - specialRoots_(NULL),
44.50 - hasPendingException_(false),
44.51 - reporter_(NULL)
44.52 -{
44.53 -}
44.54 -
44.55 -Zone::~Zone()
44.56 -{
44.57 - delete nativeTable_;
44.58 - delete types_;
44.59 - delete symbols_;
44.60 - delete packages_;
44.61 - delete globalRoots_;
44.62 -}
44.63 -
44.64 -bool
44.65 -Zone::initialize()
44.66 -{
44.67 - if (!stack_.initialize())
44.68 - return false;
44.69 - if (!heap_.initialize())
44.70 - return false;
44.71 -
44.72 - symbols_ = new StringPool(this);
44.73 - if (!symbols_ || !symbols_->initialize())
44.74 - return false;
44.75 -
44.76 - globalRoots_ = new GlobalRoots(this);
44.77 - if (!globalRoots_ || !globalRoots_->initialize())
44.78 - return false;
44.79 -
44.80 - nativeTable_ = new NativeTable(this);
44.81 - if (!nativeTable_ || !nativeTable_->initialize())
44.82 - return false;
44.83 -
44.84 - packages_ = new PackageCache(this);
44.85 - if (!packages_ || !packages_->initialize())
44.86 - return false;
44.87 -
44.88 - MapKind maps[] =
44.89 - {
44.90 - MapKind_Type,
44.91 - MapKind_ArrayType,
44.92 - MapKind_FunctionType,
44.93 - MapKind_StructType,
44.94 - MapKind_ReferenceType,
44.95 - MapKind_EnumType,
44.96 - MapKind_FixedArray,
44.97 - MapKind_ByteArray,
44.98 - MapKind_Code,
44.99 - MapKind_Reference,
44.100 - MapKind_MetaArray,
44.101 - MapKind_MetaStruct,
44.102 - MapKind_MetaEnvironment,
44.103 - MapKind_Module,
44.104 - MapKind_Function,
44.105 - MapKind_String,
44.106 - MapKind_Native,
44.107 - MapKind_Descriptor,
44.108 - MapKind_Box,
44.109 - MapKind_List,
44.110 - MapKind_Package,
44.111 - MapKind_FreeRegion,
44.112 - MapKind_EnvironmentSlotDescriptorArray
44.113 - };
44.114 -
44.115 - maps_[MapKind_Meta] = heap_.metaMap();
44.116 - for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
44.117 - if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL)
44.118 - return false;
44.119 - }
44.120 -
44.121 - types_ = new TypeManager(this);
44.122 - if (!types_ || !types_->initialize())
44.123 - return false;
44.124 -
44.125 - // Create the cached array maps for generic arrays. This is for the API
44.126 - // version of Invoke(), which needs to make arrays very quickly from C++.
44.127 - {
44.128 - // Generic "cell" array (contents do not matter, just non-gc things).
44.129 - Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
44.130 - if (!type)
44.131 - return false;
44.132 -
44.133 - type = types_->newExternalArray(type);
44.134 - if (!type)
44.135 - return false;
44.136 -
44.137 - // :TODO:
44.138 -#if 0
44.139 - externalGenericArrayMap_ = ArrayMap::Attach(this, type);
44.140 - if (!externalGenericArrayMap_)
44.141 - return false;
44.142 -#endif
44.143 -
44.144 - type = types_->getPrimitive(PrimitiveType_Char);
44.145 - if (!type)
44.146 - return false;
44.147 -
44.148 - type = types_->newExternalArray(type);
44.149 - if (!type)
44.150 - return false;
44.151 -
44.152 - // :TODO:
44.153 -#if 0
44.154 - externalCharArrayMap_ = ArrayMap::Attach(this, type);
44.155 - if (!externalCharArrayMap_)
44.156 - return false;
44.157 -#endif
44.158 - }
44.159 -
44.160 - return true;
44.161 -}
44.162 -
44.163 -Map *
44.164 -Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
44.165 -{
44.166 - assert(maps_[parent]);
44.167 - Map *map = heap_.allocateMap(kind, bytes);
44.168 - if (!map)
44.169 - return NULL;
44.170 - map->init(maps_[parent]);
44.171 - return map;
44.172 -}
44.173 -
44.174 -void
44.175 -Zone::accept(VirtualObjectVisitor *visitor)
44.176 -{
44.177 - for (unsigned i = 0; i < MapKinds_Total; i++)
44.178 - visitor->visit(maps_[i].address());
44.179 - visitor->visit(externalCharArrayMap_.address());
44.180 - visitor->visit(externalGenericArrayMap_.address());
44.181 - types()->accept(visitor);
44.182 -
44.183 - Local<Object> *local = lastLocalRoot_;
44.184 - while (local) {
44.185 - visitor->visit(local->address());
44.186 - local = local->prev();
44.187 - }
44.188 -
44.189 - globalRoots_->accept(visitor);
44.190 - rootScopes_.accept(visitor);
44.191 - nativeTable_->accept(visitor);
44.192 - packages_->accept(visitor);
44.193 -
44.194 - stack_.accept(visitor);
44.195 -}
44.196 -
44.197 -void
44.198 -Zone::sweepWeakRoots()
44.199 -{
44.200 - symbols_->sweep();
44.201 - types()->sweep();
44.202 -}
44.203 -
44.204 -String *
44.205 -Zone::makeSymbol(const char *str, size_t length)
44.206 -{
44.207 - return symbols_->add(str, length);
44.208 -}
44.209 -
44.210 -String *
44.211 -Zone::makeSymbol(const char *str)
44.212 -{
44.213 - return makeSymbol(str, strlen(str));
44.214 -}
44.215 -
44.216 -bool
44.217 -Zone::hasPendingException()
44.218 -{
44.219 - return hasPendingException_;
44.220 -}
44.221 -
44.222 -void
44.223 -Zone::reportOutOfMemory()
44.224 -{
44.225 -
44.226 -}
44.227 -
44.228 -void
44.229 -Zone::reportError(Message message, ...)
44.230 -{
44.231 - va_list ap;
44.232 - va_start(ap, message);
44.233 - reportErrorVA(message, ap);
44.234 - va_end(ap);
44.235 -}
44.236 -
44.237 -#if defined(_MSC_VER)
44.238 -# define VA_COPY(to, from) to = from
44.239 -#else
44.240 -# define VA_COPY(to, from) va_copy(to, from)
44.241 -#endif
44.242 -
44.243 -char *
44.244 -ke::BuildErrorMessage(const char *format, va_list ap)
44.245 -{
44.246 - va_list use;
44.247 - VA_COPY(use, ap);
44.248 -
44.249 - // We over-allocate and zero terminate ahead of time, since LIBCRT's
44.250 - // version of vsnprintf is screwy.
44.251 - size_t size = 255;
44.252 - char *buffer = (char *)calloc(size + 1, 1);
44.253 - if (!buffer)
44.254 - return NULL;
44.255 -
44.256 - for (;;) {
44.257 - int r = vsnprintf(buffer, size, format, use);
44.258 -
44.259 - if (r > -1 && size_t(r) < size)
44.260 - return buffer;
44.261 -
44.262 -#if defined(_MSC_VER)
44.263 - if (r < 0)
44.264 - size *= 2;
44.265 -#else
44.266 - if (r > -1)
44.267 - size = size_t(r) + 1;
44.268 - else
44.269 - size *= 2;
44.270 -#endif
44.271 -
44.272 - free(buffer);
44.273 - if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
44.274 - return NULL;
44.275 -
44.276 - VA_COPY(use, ap);
44.277 - }
44.278 -}
44.279 -
44.280 -void
44.281 -ke::FreeErrorMessage(const char *message)
44.282 -{
44.283 - free((void *)message);
44.284 -}
44.285 -
44.286 -void
44.287 -Zone::reportErrorVA(Message message, va_list ap)
44.288 -{
44.289 - char *report = BuildErrorMessage(Messages[message].format, ap);
44.290 - if (!report) {
44.291 - reportOutOfMemory();
44.292 - return;
44.293 - }
44.294 -
44.295 - if (reporter_) {
44.296 - // Reporters can re-enter. When we start having actual exception
44.297 - // objects that can be caught and inspected, this code will have to
44.298 - // save and restore the exception state.
44.299 - reporter_->onUncaughtException(report);
44.300 - }
44.301 -
44.302 - hasPendingException_ = true;
44.303 -
44.304 - FreeErrorMessage(report);
44.305 -}
44.306 -
44.307 -void
44.308 -Zone::installErrorReporter(Ke::IMessageReporter *reporter)
44.309 -{
44.310 - reporter_ = reporter;
44.311 -}
44.312 -
44.313 -void
44.314 -ZoneAllocatorPolicy::reportOutOfMemory()
44.315 -{
44.316 - ZONE()->reportOutOfMemory();
44.317 -}
44.318 -
44.319 -void
44.320 -ZoneAllocatorPolicy::reportAllocationOverflow()
44.321 -{
44.322 - ZONE()->reportAllocationOverflow();
44.323 -}
44.324 -
44.325 -void
44.326 -Zone::reportAllocationOverflow()
44.327 -{
44.328 - reportError(Message_AllocationOverflow);
44.329 -}
44.330 -
44.331 -void
44.332 -Zone::clearPendingException()
44.333 -{
44.334 - hasPendingException_ = false;
44.335 -}
44.336 -
44.337 -void
44.338 -Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
44.339 -{
44.340 - publicFunctionListener_ = listener;
44.341 -}
44.342 -
44.343 -void *
44.344 -Zone::malloc(size_t size)
44.345 -{
44.346 - void *ptr = ::malloc(size);
44.347 - if (!ptr)
44.348 - reportOutOfMemory();
44.349 - return ptr;
44.350 -}
44.351 -
44.352 -void *
44.353 -Zone::realloc(void *ptr, size_t size)
44.354 -{
44.355 - ptr = ::realloc(ptr, size);
44.356 - if (!ptr)
44.357 - reportOutOfMemory();
44.358 - return ptr;
44.359 -}
44.360 -
44.361 -AutoRooted::AutoRooted(Zone *zone)
44.362 - : zone_(zone),
44.363 - prev_(*zone->lastSpecialRoot())
44.364 -{
44.365 - *zone->lastSpecialRoot() = this;
44.366 -}
44.367 -
44.368 -AutoRooted::~AutoRooted()
44.369 -{
44.370 - *zone_->lastSpecialRoot() = prev_;
44.371 -}
44.372 +/* vim: set ts=4 sw=4 tw=99 et:
44.373 + *
44.374 + * Copyright (C) 2012 David Anderson
44.375 + *
44.376 + * This file is part of JITCraft.
44.377 + *
44.378 + * JITCraft is free software: you can redistribute it and/or modify it under
44.379 + * the terms of the GNU General Public License as published by the Free
44.380 + * Software Foundation, either version 3 of the License, or (at your option)
44.381 + * any later version.
44.382 + *
44.383 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
44.384 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
44.385 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
44.386 + *
44.387 + * You should have received a copy of the GNU General Public License along with
44.388 + * JITCraft. If not, see http://www.gnu.org/licenses/.
44.389 + */
44.390 +#include <stdlib.h>
44.391 +#include "Zone.h"
44.392 +#include "StringPool.h"
44.393 +#include "TypeManager.h"
44.394 +#include "GlobalRoots.h"
44.395 +#include "AllocatorPolicies.h"
44.396 +#include "Array.h"
44.397 +#include "NativeTable.h"
44.398 +#include "Packages.h"
44.399 +#include "Spaces-inl.h"
44.400 +#include "Heap-inl.h"
44.401 +
44.402 +using namespace ke;
44.403 +
44.404 +Zone *ke::SingleThreadedZone;
44.405 +
44.406 +void * const NullAddress::Sentinel = NULL;
44.407 +
44.408 +Zone::Zone()
44.409 + : stack_(thisFromCtor()),
44.410 + heap_(thisFromCtor()),
44.411 + types_(NULL),
44.412 + symbols_(NULL),
44.413 + globalRoots_(NULL),
44.414 + nativeTable_(NULL),
44.415 + packages_(NULL),
44.416 + lastLocalRoot_(NULL),
44.417 + specialRoots_(NULL),
44.418 + hasPendingException_(false),
44.419 + reporter_(NULL)
44.420 +{
44.421 +}
44.422 +
44.423 +Zone::~Zone()
44.424 +{
44.425 + delete nativeTable_;
44.426 + delete types_;
44.427 + delete symbols_;
44.428 + delete packages_;
44.429 + delete globalRoots_;
44.430 +}
44.431 +
44.432 +bool
44.433 +Zone::initialize()
44.434 +{
44.435 + if (!stack_.initialize())
44.436 + return false;
44.437 + if (!heap_.initialize())
44.438 + return false;
44.439 +
44.440 + symbols_ = new StringPool(this);
44.441 + if (!symbols_ || !symbols_->initialize())
44.442 + return false;
44.443 +
44.444 + globalRoots_ = new GlobalRoots(this);
44.445 + if (!globalRoots_ || !globalRoots_->initialize())
44.446 + return false;
44.447 +
44.448 + nativeTable_ = new NativeTable(this);
44.449 + if (!nativeTable_ || !nativeTable_->initialize())
44.450 + return false;
44.451 +
44.452 + packages_ = new PackageCache(this);
44.453 + if (!packages_ || !packages_->initialize())
44.454 + return false;
44.455 +
44.456 + MapKind maps[] =
44.457 + {
44.458 + MapKind_Type,
44.459 + MapKind_ArrayType,
44.460 + MapKind_FunctionType,
44.461 + MapKind_StructType,
44.462 + MapKind_ReferenceType,
44.463 + MapKind_EnumType,
44.464 + MapKind_FixedArray,
44.465 + MapKind_ByteArray,
44.466 + MapKind_Code,
44.467 + MapKind_Reference,
44.468 + MapKind_MetaArray,
44.469 + MapKind_MetaStruct,
44.470 + MapKind_MetaEnvironment,
44.471 + MapKind_Module,
44.472 + MapKind_Function,
44.473 + MapKind_String,
44.474 + MapKind_Native,
44.475 + MapKind_Descriptor,
44.476 + MapKind_Box,
44.477 + MapKind_List,
44.478 + MapKind_Package,
44.479 + MapKind_FreeRegion,
44.480 + MapKind_EnvironmentSlotDescriptorArray
44.481 + };
44.482 +
44.483 + maps_[MapKind_Meta] = heap_.metaMap();
44.484 + for (size_t i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
44.485 + if ((maps_[maps[i]] = allocateMap(maps[i], sizeof(Map))) == NULL)
44.486 + return false;
44.487 + }
44.488 +
44.489 + types_ = new TypeManager(this);
44.490 + if (!types_ || !types_->initialize())
44.491 + return false;
44.492 +
44.493 + // Create the cached array maps for generic arrays. This is for the API
44.494 + // version of Invoke(), which needs to make arrays very quickly from C++.
44.495 + {
44.496 + // Generic "cell" array (contents do not matter, just non-gc things).
44.497 + Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
44.498 + if (!type)
44.499 + return false;
44.500 +
44.501 + type = types_->newExternalArray(type);
44.502 + if (!type)
44.503 + return false;
44.504 +
44.505 + // :TODO:
44.506 +#if 0
44.507 + externalGenericArrayMap_ = ArrayMap::Attach(this, type);
44.508 + if (!externalGenericArrayMap_)
44.509 + return false;
44.510 +#endif
44.511 +
44.512 + type = types_->getPrimitive(PrimitiveType_Char);
44.513 + if (!type)
44.514 + return false;
44.515 +
44.516 + type = types_->newExternalArray(type);
44.517 + if (!type)
44.518 + return false;
44.519 +
44.520 + // :TODO:
44.521 +#if 0
44.522 + externalCharArrayMap_ = ArrayMap::Attach(this, type);
44.523 + if (!externalCharArrayMap_)
44.524 + return false;
44.525 +#endif
44.526 + }
44.527 +
44.528 + return true;
44.529 +}
44.530 +
44.531 +Map *
44.532 +Zone::allocateMap(MapKind kind, size_t bytes, MapKind parent)
44.533 +{
44.534 + assert(maps_[parent]);
44.535 + Map *map = heap_.allocateMap(kind, bytes);
44.536 + if (!map)
44.537 + return NULL;
44.538 + map->init(maps_[parent]);
44.539 + return map;
44.540 +}
44.541 +
44.542 +void
44.543 +Zone::accept(VirtualObjectVisitor *visitor)
44.544 +{
44.545 + for (unsigned i = 0; i < MapKinds_Total; i++)
44.546 + visitor->visit(maps_[i].address());
44.547 + visitor->visit(externalCharArrayMap_.address());
44.548 + visitor->visit(externalGenericArrayMap_.address());
44.549 + types()->accept(visitor);
44.550 +
44.551 + Local<Object> *local = lastLocalRoot_;
44.552 + while (local) {
44.553 + visitor->visit(local->address());
44.554 + local = local->prev();
44.555 + }
44.556 +
44.557 + globalRoots_->accept(visitor);
44.558 + rootScopes_.accept(visitor);
44.559 + nativeTable_->accept(visitor);
44.560 + packages_->accept(visitor);
44.561 +
44.562 + stack_.accept(visitor);
44.563 +}
44.564 +
44.565 +void
44.566 +Zone::sweepWeakRoots()
44.567 +{
44.568 + symbols_->sweep();
44.569 + types()->sweep();
44.570 +}
44.571 +
44.572 +String *
44.573 +Zone::makeSymbol(const char *str, size_t length)
44.574 +{
44.575 + return symbols_->add(str, length);
44.576 +}
44.577 +
44.578 +String *
44.579 +Zone::makeSymbol(const char *str)
44.580 +{
44.581 + return makeSymbol(str, strlen(str));
44.582 +}
44.583 +
44.584 +bool
44.585 +Zone::hasPendingException()
44.586 +{
44.587 + return hasPendingException_;
44.588 +}
44.589 +
44.590 +void
44.591 +Zone::reportOutOfMemory()
44.592 +{
44.593 +
44.594 +}
44.595 +
44.596 +void
44.597 +Zone::reportError(Message message, ...)
44.598 +{
44.599 + va_list ap;
44.600 + va_start(ap, message);
44.601 + reportErrorVA(message, ap);
44.602 + va_end(ap);
44.603 +}
44.604 +
44.605 +#if defined(_MSC_VER)
44.606 +# define VA_COPY(to, from) to = from
44.607 +#else
44.608 +# define VA_COPY(to, from) va_copy(to, from)
44.609 +#endif
44.610 +
44.611 +char *
44.612 +ke::BuildErrorMessage(const char *format, va_list ap)
44.613 +{
44.614 + va_list use;
44.615 + VA_COPY(use, ap);
44.616 +
44.617 + // We over-allocate and zero terminate ahead of time, since LIBCRT's
44.618 + // version of vsnprintf is screwy.
44.619 + size_t size = 255;
44.620 + char *buffer = (char *)calloc(size + 1, 1);
44.621 + if (!buffer)
44.622 + return NULL;
44.623 +
44.624 + for (;;) {
44.625 + int r = vsnprintf(buffer, size, format, use);
44.626 +
44.627 + if (r > -1 && size_t(r) < size)
44.628 + return buffer;
44.629 +
44.630 +#if defined(_MSC_VER)
44.631 + if (r < 0)
44.632 + size *= 2;
44.633 +#else
44.634 + if (r > -1)
44.635 + size = size_t(r) + 1;
44.636 + else
44.637 + size *= 2;
44.638 +#endif
44.639 +
44.640 + free(buffer);
44.641 + if ((buffer = (char *)calloc(size + 1, 1)) == NULL)
44.642 + return NULL;
44.643 +
44.644 + VA_COPY(use, ap);
44.645 + }
44.646 +}
44.647 +
44.648 +void
44.649 +ke::FreeErrorMessage(const char *message)
44.650 +{
44.651 + free((void *)message);
44.652 +}
44.653 +
44.654 +void
44.655 +Zone::reportErrorVA(Message message, va_list ap)
44.656 +{
44.657 + char *report = BuildErrorMessage(Messages[message].format, ap);
44.658 + if (!report) {
44.659 + reportOutOfMemory();
44.660 + return;
44.661 + }
44.662 +
44.663 + if (reporter_) {
44.664 + // Reporters can re-enter. When we start having actual exception
44.665 + // objects that can be caught and inspected, this code will have to
44.666 + // save and restore the exception state.
44.667 + reporter_->onUncaughtException(report);
44.668 + }
44.669 +
44.670 + hasPendingException_ = true;
44.671 +
44.672 + FreeErrorMessage(report);
44.673 +}
44.674 +
44.675 +void
44.676 +Zone::installErrorReporter(Ke::IMessageReporter *reporter)
44.677 +{
44.678 + reporter_ = reporter;
44.679 +}
44.680 +
44.681 +void
44.682 +ZoneAllocatorPolicy::reportOutOfMemory()
44.683 +{
44.684 + ZONE()->reportOutOfMemory();
44.685 +}
44.686 +
44.687 +void
44.688 +ZoneAllocatorPolicy::reportAllocationOverflow()
44.689 +{
44.690 + ZONE()->reportAllocationOverflow();
44.691 +}
44.692 +
44.693 +void
44.694 +Zone::reportAllocationOverflow()
44.695 +{
44.696 + reportError(Message_AllocationOverflow);
44.697 +}
44.698 +
44.699 +void
44.700 +Zone::clearPendingException()
44.701 +{
44.702 + hasPendingException_ = false;
44.703 +}
44.704 +
44.705 +void
44.706 +Zone::setPublicFunctionListener(Ke::IPublicFunctionListener *listener)
44.707 +{
44.708 + publicFunctionListener_ = listener;
44.709 +}
44.710 +
44.711 +void *
44.712 +Zone::malloc(size_t size)
44.713 +{
44.714 + void *ptr = ::malloc(size);
44.715 + if (!ptr)
44.716 + reportOutOfMemory();
44.717 + return ptr;
44.718 +}
44.719 +
44.720 +void *
44.721 +Zone::realloc(void *ptr, size_t size)
44.722 +{
44.723 + ptr = ::realloc(ptr, size);
44.724 + if (!ptr)
44.725 + reportOutOfMemory();
44.726 + return ptr;
44.727 +}
44.728 +
44.729 +AutoRooted::AutoRooted(Zone *zone)
44.730 + : zone_(zone),
44.731 + prev_(*zone->lastSpecialRoot())
44.732 +{
44.733 + *zone->lastSpecialRoot() = this;
44.734 +}
44.735 +
44.736 +AutoRooted::~AutoRooted()
44.737 +{
44.738 + *zone_->lastSpecialRoot() = prev_;
44.739 +}
45.1 --- a/src/Zone.h Mon Jun 10 00:46:29 2013 +0100
45.2 +++ b/src/Zone.h Mon Jun 10 01:04:43 2013 +0100
45.3 @@ -1,221 +1,221 @@
45.4 -/* vim: set ts=4 sw=4 tw=99 et:
45.5 - *
45.6 - * Copyright (C) 2012 David Anderson
45.7 - *
45.8 - * This file is part of SourcePawn.
45.9 - *
45.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
45.11 - * the terms of the GNU General Public License as published by the Free
45.12 - * Software Foundation, either version 3 of the License, or (at your option)
45.13 - * any later version.
45.14 - *
45.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
45.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
45.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
45.18 - *
45.19 - * You should have received a copy of the GNU General Public License along with
45.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
45.21 - */
45.22 -#ifndef _include_jitcraft_thread_h_
45.23 -#define _include_jitcraft_thread_h_
45.24 -
45.25 -#include <stdarg.h>
45.26 -#include "PoolAllocator.h"
45.27 -#include "Stack.h"
45.28 -#include "Heap.h"
45.29 -#include "Barriers.h"
45.30 -#include "Handles.h"
45.31 -#include "Messages.h"
45.32 -#include "RootScopes.h"
45.33 -#include "VirtualObjectVisitor.h"
45.34 -
45.35 -namespace ke {
45.36 -
45.37 -class TypeManager;
45.38 -class String;
45.39 -class StringPool;
45.40 -class GlobalRoots;
45.41 -class ArrayMap;
45.42 -class Exception;
45.43 -class NativeTable;
45.44 -class PackageCache;
45.45 -
45.46 -class Zone
45.47 -{
45.48 - PoolAllocator pool_;
45.49 - Stack stack_;
45.50 - Heap heap_;
45.51 -
45.52 - // Map cache.
45.53 - Unbarriered<Map> maps_[MapKinds_Total];
45.54 - Unbarriered<ArrayMap> externalGenericArrayMap_;
45.55 - Unbarriered<ArrayMap> externalCharArrayMap_;
45.56 -
45.57 - TypeManager *types_;
45.58 - StringPool *symbols_;
45.59 - GlobalRoots *globalRoots_;
45.60 - NativeTable *nativeTable_;
45.61 - PackageCache *packages_;
45.62 -
45.63 - // Root list.
45.64 - Local<Object> *lastLocalRoot_;
45.65 - RootScopeManager rootScopes_;
45.66 - AutoRooted *specialRoots_;
45.67 -
45.68 - // Exception stuff.
45.69 - bool hasPendingException_;
45.70 - Ke::IMessageReporter *reporter_;
45.71 -
45.72 - Ke::IPublicFunctionListener *publicFunctionListener_;
45.73 -
45.74 - private:
45.75 - Zone *thisFromCtor() {
45.76 - return this;
45.77 - }
45.78 -
45.79 - public:
45.80 - Zone();
45.81 - ~Zone();
45.82 - bool initialize();
45.83 -
45.84 - PoolAllocator &pool() {
45.85 - return pool_;
45.86 - }
45.87 - Stack &stack() {
45.88 - return stack_;
45.89 - }
45.90 - Heap &heap() {
45.91 - return heap_;
45.92 - }
45.93 - Object *allocate(MapKind kind, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
45.94 - assert(maps_[kind]);
45.95 - Local<Map> map(this, maps_[kind]);
45.96 - return allocate(map, bytes, tenure);
45.97 - }
45.98 - Object *allocate(Handle<Map> map, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
45.99 - return heap_.allocate(map, bytes, tenure);
45.100 - }
45.101 - Map *getMap(MapKind kind) {
45.102 - return maps_[kind];
45.103 - }
45.104 - Map *allocateMap(MapKind kind, size_t bytes, MapKind parent = MapKind_Meta);
45.105 -
45.106 - ArrayMap *externalGenericArrayMap() {
45.107 - return externalGenericArrayMap_;
45.108 - }
45.109 - ArrayMap *externalCharArrayMap() {
45.110 - return externalCharArrayMap_;
45.111 - }
45.112 -
45.113 - TypeManager *types() const {
45.114 - return types_;
45.115 - }
45.116 - AutoRooted **lastSpecialRoot() {
45.117 - return &specialRoots_;
45.118 - }
45.119 - Local<Object> **lastLocalRoot() {
45.120 - return &lastLocalRoot_;
45.121 - }
45.122 - Object **makeScopedRoot(Object *ptr) {
45.123 - return rootScopes_.make(ptr);
45.124 - }
45.125 - RootScopeManager &rootScopes() {
45.126 - return rootScopes_;
45.127 - }
45.128 - StringPool *symbols() {
45.129 - return symbols_;
45.130 - }
45.131 - GlobalRoots *globalRoots() {
45.132 - return globalRoots_;
45.133 - }
45.134 - NativeTable *nativeTable() {
45.135 - return nativeTable_;
45.136 - }
45.137 - PackageCache *packages() {
45.138 - return packages_;
45.139 - }
45.140 -
45.141 - String *makeSymbol(const char *string, size_t length);
45.142 - String *makeSymbol(const char *string);
45.143 -
45.144 - void reportOutOfMemory();
45.145 - void reportAllocationOverflow();
45.146 - void reportError(Message message, ...);
45.147 - void reportErrorVA(Message message, va_list ap);
45.148 - bool hasPendingException();
45.149 - void clearPendingException();
45.150 - void installErrorReporter(Ke::IMessageReporter *reporter);
45.151 - Ke::IMessageReporter *errorReporter() {
45.152 - return reporter_;
45.153 - }
45.154 -
45.155 - void accept(VirtualObjectVisitor *visitor);
45.156 - void sweepWeakRoots();
45.157 -
45.158 - void setPublicFunctionListener(Ke::IPublicFunctionListener *listener);
45.159 - void registerPublic(Handle<Function> fun);
45.160 - void unregisterPublic(Handle<Function> fun);
45.161 -
45.162 - // Helpers that report OOM.
45.163 - void *malloc(size_t size);
45.164 - void *realloc(void *ptr, size_t size);
45.165 -};
45.166 -
45.167 -// In a multi-threaded system, this would be a TLS variable.
45.168 -// In the interest of simplicity, we are single-threaded for now.
45.169 -extern Zone *SingleThreadedZone;
45.170 -
45.171 -// Exposed for the compiler.
45.172 -char *BuildErrorMessage(const char *format, va_list ap);
45.173 -void FreeErrorMessage(const char *message);
45.174 -
45.175 -static inline Zone *ZONE()
45.176 -{
45.177 - return SingleThreadedZone;
45.178 -}
45.179 -
45.180 -template <typename T>
45.181 -Local<T>::Local(Zone *zone, T *thing)
45.182 - : zone_(zone),
45.183 - thing_(thing),
45.184 - prev_(*zone->lastLocalRoot())
45.185 -{
45.186 - *zone->lastLocalRoot() = toRaw();
45.187 -}
45.188 -
45.189 -template <typename T>
45.190 -
45.191 -Local<T>::~Local()
45.192 -{
45.193 - assert(*zone_->lastLocalRoot() == toRaw());
45.194 - *zone_->lastLocalRoot() = prev_;
45.195 -}
45.196 -
45.197 -template <typename T>
45.198 -ScopedRoot<T>::ScopedRoot()
45.199 - : thingp_(make(NULL))
45.200 -{
45.201 -}
45.202 -
45.203 -template <typename T>
45.204 -ScopedRoot<T>::ScopedRoot(T *thing)
45.205 - : thingp_(make(thing))
45.206 -{
45.207 - // Type check that T is an Object.
45.208 - (void)static_cast<Object *>(thing);
45.209 -}
45.210 -
45.211 -template <typename T> T **
45.212 -ScopedRoot<T>::make(T *other)
45.213 -{
45.214 - return reinterpret_cast<T **>(ZONE()->makeScopedRoot(other));
45.215 -}
45.216 -
45.217 -RootScope::RootScope(Zone *zone)
45.218 - : Ke::HandleScope(zone, zone->rootScopes().position(), *zone->rootScopes().scope())
45.219 -{
45.220 -}
45.221 -
45.222 -}
45.223 -
45.224 -#endif // _include_jitcraft_thread_h_
45.225 +/* vim: set ts=4 sw=4 tw=99 et:
45.226 + *
45.227 + * Copyright (C) 2012 David Anderson
45.228 + *
45.229 + * This file is part of SourcePawn.
45.230 + *
45.231 + * SourcePawn is free software: you can redistribute it and/or modify it under
45.232 + * the terms of the GNU General Public License as published by the Free
45.233 + * Software Foundation, either version 3 of the License, or (at your option)
45.234 + * any later version.
45.235 + *
45.236 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
45.237 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
45.238 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
45.239 + *
45.240 + * You should have received a copy of the GNU General Public License along with
45.241 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
45.242 + */
45.243 +#ifndef _include_jitcraft_thread_h_
45.244 +#define _include_jitcraft_thread_h_
45.245 +
45.246 +#include <stdarg.h>
45.247 +#include "PoolAllocator.h"
45.248 +#include "Stack.h"
45.249 +#include "Heap.h"
45.250 +#include "Barriers.h"
45.251 +#include "Handles.h"
45.252 +#include "Messages.h"
45.253 +#include "RootScopes.h"
45.254 +#include "VirtualObjectVisitor.h"
45.255 +
45.256 +namespace ke {
45.257 +
45.258 +class TypeManager;
45.259 +class String;
45.260 +class StringPool;
45.261 +class GlobalRoots;
45.262 +class ArrayMap;
45.263 +class Exception;
45.264 +class NativeTable;
45.265 +class PackageCache;
45.266 +
45.267 +class Zone
45.268 +{
45.269 + PoolAllocator pool_;
45.270 + Stack stack_;
45.271 + Heap heap_;
45.272 +
45.273 + // Map cache.
45.274 + Unbarriered<Map> maps_[MapKinds_Total];
45.275 + Unbarriered<ArrayMap> externalGenericArrayMap_;
45.276 + Unbarriered<ArrayMap> externalCharArrayMap_;
45.277 +
45.278 + TypeManager *types_;
45.279 + StringPool *symbols_;
45.280 + GlobalRoots *globalRoots_;
45.281 + NativeTable *nativeTable_;
45.282 + PackageCache *packages_;
45.283 +
45.284 + // Root list.
45.285 + Local<Object> *lastLocalRoot_;
45.286 + RootScopeManager rootScopes_;
45.287 + AutoRooted *specialRoots_;
45.288 +
45.289 + // Exception stuff.
45.290 + bool hasPendingException_;
45.291 + Ke::IMessageReporter *reporter_;
45.292 +
45.293 + Ke::IPublicFunctionListener *publicFunctionListener_;
45.294 +
45.295 + private:
45.296 + Zone *thisFromCtor() {
45.297 + return this;
45.298 + }
45.299 +
45.300 + public:
45.301 + Zone();
45.302 + ~Zone();
45.303 + bool initialize();
45.304 +
45.305 + PoolAllocator &pool() {
45.306 + return pool_;
45.307 + }
45.308 + Stack &stack() {
45.309 + return stack_;
45.310 + }
45.311 + Heap &heap() {
45.312 + return heap_;
45.313 + }
45.314 + Object *allocate(MapKind kind, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
45.315 + assert(maps_[kind]);
45.316 + Local<Map> map(this, maps_[kind]);
45.317 + return allocate(map, bytes, tenure);
45.318 + }
45.319 + Object *allocate(Handle<Map> map, size_t bytes, Heap::Tenure tenure = Heap::Tenure_Default) {
45.320 + return heap_.allocate(map, bytes, tenure);
45.321 + }
45.322 + Map *getMap(MapKind kind) {
45.323 + return maps_[kind];
45.324 + }
45.325 + Map *allocateMap(MapKind kind, size_t bytes, MapKind parent = MapKind_Meta);
45.326 +
45.327 + ArrayMap *externalGenericArrayMap() {
45.328 + return externalGenericArrayMap_;
45.329 + }
45.330 + ArrayMap *externalCharArrayMap() {
45.331 + return externalCharArrayMap_;
45.332 + }
45.333 +
45.334 + TypeManager *types() const {
45.335 + return types_;
45.336 + }
45.337 + AutoRooted **lastSpecialRoot() {
45.338 + return &specialRoots_;
45.339 + }
45.340 + Local<Object> **lastLocalRoot() {
45.341 + return &lastLocalRoot_;
45.342 + }
45.343 + Object **makeScopedRoot(Object *ptr) {
45.344 + return rootScopes_.make(ptr);
45.345 + }
45.346 + RootScopeManager &rootScopes() {
45.347 + return rootScopes_;
45.348 + }
45.349 + StringPool *symbols() {
45.350 + return symbols_;
45.351 + }
45.352 + GlobalRoots *globalRoots() {
45.353 + return globalRoots_;
45.354 + }
45.355 + NativeTable *nativeTable() {
45.356 + return nativeTable_;
45.357 + }
45.358 + PackageCache *packages() {
45.359 + return packages_;
45.360 + }
45.361 +
45.362 + String *makeSymbol(const char *string, size_t length);
45.363 + String *makeSymbol(const char *string);
45.364 +
45.365 + void reportOutOfMemory();
45.366 + void reportAllocationOverflow();
45.367 + void reportError(Message message, ...);
45.368 + void reportErrorVA(Message message, va_list ap);
45.369 + bool hasPendingException();
45.370 + void clearPendingException();
45.371 + void installErrorReporter(Ke::IMessageReporter *reporter);
45.372 + Ke::IMessageReporter *errorReporter() {
45.373 + return reporter_;
45.374 + }
45.375 +
45.376 + void accept(VirtualObjectVisitor *visitor);
45.377 + void sweepWeakRoots();
45.378 +
45.379 + void setPublicFunctionListener(Ke::IPublicFunctionListener *listener);
45.380 + void registerPublic(Handle<Function> fun);
45.381 + void unregisterPublic(Handle<Function> fun);
45.382 +
45.383 + // Helpers that report OOM.
45.384 + void *malloc(size_t size);
45.385 + void *realloc(void *ptr, size_t size);
45.386 +};
45.387 +
45.388 +// In a multi-threaded system, this would be a TLS variable.
45.389 +// In the interest of simplicity, we are single-threaded for now.
45.390 +extern Zone *SingleThreadedZone;
45.391 +
45.392 +// Exposed for the compiler.
45.393 +char *BuildErrorMessage(const char *format, va_list ap);
45.394 +void FreeErrorMessage(const char *message);
45.395 +
45.396 +static inline Zone *ZONE()
45.397 +{
45.398 + return SingleThreadedZone;
45.399 +}
45.400 +
45.401 +template <typename T>
45.402 +Local<T>::Local(Zone *zone, T *thing)
45.403 + : zone_(zone),
45.404 + thing_(thing),
45.405 + prev_(*zone->lastLocalRoot())
45.406 +{
45.407 + *zone->lastLocalRoot() = toRaw();
45.408 +}
45.409 +
45.410 +template <typename T>
45.411 +
45.412 +Local<T>::~Local()
45.413 +{
45.414 + assert(*zone_->lastLocalRoot() == toRaw());
45.415 + *zone_->lastLocalRoot() = prev_;
45.416 +}
45.417 +
45.418 +template <typename T>
45.419 +ScopedRoot<T>::ScopedRoot()
45.420 + : thingp_(make(NULL))
45.421 +{
45.422 +}
45.423 +
45.424 +template <typename T>
45.425 +ScopedRoot<T>::ScopedRoot(T *thing)
45.426 + : thingp_(make(thing))
45.427 +{
45.428 + // Type check that T is an Object.
45.429 + (void)static_cast<Object *>(thing);
45.430 +}
45.431 +
45.432 +template <typename T> T **
45.433 +ScopedRoot<T>::make(T *other)
45.434 +{
45.435 + return reinterpret_cast<T **>(ZONE()->makeScopedRoot(other));
45.436 +}
45.437 +
45.438 +RootScope::RootScope(Zone *zone)
45.439 + : Ke::HandleScope(zone, zone->rootScopes().position(), *zone->rootScopes().scope())
45.440 +{
45.441 +}
45.442 +
45.443 +}
45.444 +
45.445 +#endif // _include_jitcraft_thread_h_
46.1 --- a/src/compiler/AST.h Mon Jun 10 00:46:29 2013 +0100
46.2 +++ b/src/compiler/AST.h Mon Jun 10 01:04:43 2013 +0100
46.3 @@ -1,1169 +1,1169 @@
46.4 -/* vim: set ts=4 sw=4 tw=99 et:
46.5 - *
46.6 - * Copyright (C) 2012 David Anderson
46.7 - *
46.8 - * This file is part of SourcePawn.
46.9 - *
46.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
46.11 - * the terms of the GNU General Public License as published by the Free
46.12 - * Software Foundation, either version 3 of the License, or (at your option)
46.13 - * any later version.
46.14 - *
46.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
46.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
46.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
46.18 - *
46.19 - * You should have received a copy of the GNU General Public License along with
46.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
46.21 - */
46.22 -#ifndef _include_sourcepawn_ast_h_
46.23 -#define _include_sourcepawn_ast_h_
46.24 -
46.25 -#include "../PoolAllocator.h"
46.26 -#include "../Vector.h"
46.27 -#include "Token.h"
46.28 -#include "NameBinding.h"
46.29 -#include "Symbols.h"
46.30 -
46.31 -namespace ke {
46.32 -
46.33 -class Scope;
46.34 -class Importable;
46.35 -struct PathComponent;
46.36 -
46.37 -#define ASTKINDS(_) \
46.38 - _(VariableDeclaration) \
46.39 - _(ForStatement) \
46.40 - _(ReturnStatement) \
46.41 - _(IntegerLiteral) \
46.42 - _(FloatLiteral) \
46.43 - _(StringLiteral) \
46.44 - _(BinaryExpression) \
46.45 - _(BlockStatement) \
46.46 - _(Assignment) \
46.47 - _(NameProxy) \
46.48 - _(ExpressionStatement) \
46.49 - _(FunctionStatement) \
46.50 - _(CallExpression) \
46.51 - _(IfStatement) \
46.52 - _(IndexExpression) \
46.53 - _(FieldExpression) \
46.54 - _(EnumStatement) \
46.55 - _(WhileStatement) \
46.56 - _(BreakStatement) \
46.57 - _(ContinueStatement) \
46.58 - _(FunctionTypeStatement) \
46.59 - _(IncDecExpression) \
46.60 - _(UnaryExpression) \
46.61 - _(TernaryExpression) \
46.62 - _(BooleanLiteral) \
46.63 - _(StructureStatement) \
46.64 - _(SwitchStatement) \
46.65 - _(ArrayLiteral) \
46.66 - _(ImportStatement)
46.67 -
46.68 -// Forward declarations.
46.69 -#define _(name) class name;
46.70 -ASTKINDS(_)
46.71 -#undef _
46.72 -
46.73 -class AstVisitor;
46.74 -
46.75 -// Interface for AST nodes.
46.76 -class AstNode : public PoolObject
46.77 -{
46.78 - SourcePosition pos_;
46.79 -
46.80 - public:
46.81 - enum Kind {
46.82 -# define _(name) k##name,
46.83 - ASTKINDS(_)
46.84 -# undef _
46.85 - AstKind_Invalid
46.86 - };
46.87 -
46.88 - AstNode(const SourcePosition &pos)
46.89 - : pos_(pos)
46.90 - {
46.91 - }
46.92 -
46.93 - virtual Kind kind() const = 0;
46.94 -
46.95 -#define _(name) bool is##name() { return kind() == k##name; } \
46.96 - name *to##name() { assert(is##name()); return (name *)this; } \
46.97 - name *as##name() { if (!is##name()) return NULL; return to##name(); }
46.98 - ASTKINDS(_)
46.99 -#undef _
46.100 -
46.101 - virtual void accept(AstVisitor *visitor) = 0;
46.102 -
46.103 - const SourcePosition &pos() const {
46.104 - return pos_;
46.105 - }
46.106 -};
46.107 -
46.108 -#define DECLARE_NODE(type) \
46.109 - Kind kind() const { \
46.110 - return k##type; \
46.111 - } \
46.112 - void accept(AstVisitor *visitor) { \
46.113 - visitor->visit##type(this); \
46.114 - }
46.115 -
46.116 -class AstVisitor
46.117 -{
46.118 - public:
46.119 -#define _(name) virtual void visit##name(name *node) { assert(false); }
46.120 - ASTKINDS(_)
46.121 -#undef _
46.122 -};
46.123 -
46.124 -class Statement : public AstNode
46.125 -{
46.126 - public:
46.127 - Statement(const SourcePosition &pos)
46.128 - : AstNode(pos)
46.129 - {
46.130 - }
46.131 -};
46.132 -
46.133 -class Expression : public AstNode
46.134 -{
46.135 - public:
46.136 - Expression(const SourcePosition &pos)
46.137 - : AstNode(pos)
46.138 - {
46.139 - }
46.140 -};
46.141 -
46.142 -typedef PoolList<Statement *> StatementList;
46.143 -typedef PoolList<Expression *> ExpressionList;
46.144 -
46.145 -class VariableDeclaration : public Statement
46.146 -{
46.147 - TypeQualifiers qual_;
46.148 - ScopedRoot<String> name_;
46.149 - Expression *initialization_;
46.150 - ExpressionList *dims_;
46.151 - Expression *type_;
46.152 - VariableSymbol *sym_;
46.153 -
46.154 - public:
46.155 - VariableDeclaration(const SourcePosition &pos, TypeQualifiers qual, Handle<String> name,
46.156 - Expression *type, ExpressionList *dims, Expression *initialization)
46.157 - : Statement(pos),
46.158 - qual_(qual),
46.159 - name_(name),
46.160 - initialization_(initialization),
46.161 - dims_(dims),
46.162 - type_(type),
46.163 - sym_(NULL)
46.164 - {
46.165 - }
46.166 -
46.167 - DECLARE_NODE(VariableDeclaration);
46.168 -
46.169 - Expression *initialization() const {
46.170 - return initialization_;
46.171 - }
46.172 - Handle<String> name() {
46.173 - return name_;
46.174 - }
46.175 - Expression *declType() const {
46.176 - return type_;
46.177 - }
46.178 - void setSymbol(VariableSymbol *sym) {
46.179 - assert(!sym_);
46.180 - sym_ = sym;
46.181 - }
46.182 - VariableSymbol *sym() const {
46.183 - return sym_;
46.184 - }
46.185 - Expression *type() const {
46.186 - return type_;
46.187 - }
46.188 - ExpressionList *dims() const {
46.189 - return dims_;
46.190 - }
46.191 - TypeQualifiers quals() const {
46.192 - return qual_;
46.193 - }
46.194 -};
46.195 -
46.196 -class Parameter : public PoolObject
46.197 -{
46.198 - ScopedRoot<String> name_;
46.199 - Expression *type_;
46.200 - bool reference_;
46.201 - Expression *initializer_;
46.202 - VariableSymbol *sym_;
46.203 - SourcePosition pos_;
46.204 - ExpressionList *dims_;
46.205 - TypeQualifiers quals_;
46.206 -
46.207 - public:
46.208 - Parameter(Handle<String> name, Expression *type, bool reference, TypeQualifiers quals,
46.209 - ExpressionList *dims, Expression *initializer, const SourcePosition &pos)
46.210 - : name_(name),
46.211 - type_(type),
46.212 - reference_(reference),
46.213 - initializer_(initializer),
46.214 - sym_(NULL),
46.215 - pos_(pos),
46.216 - dims_(dims),
46.217 - quals_(quals)
46.218 - {
46.219 - }
46.220 -
46.221 - Expression *type() const {
46.222 - return type_;
46.223 - }
46.224 - Handle<String> name() const {
46.225 - return name_;
46.226 - }
46.227 - bool reference() const {
46.228 - return reference_;
46.229 - }
46.230 - TypeQualifiers quals() const {
46.231 - return quals_;
46.232 - }
46.233 - ExpressionList *dims() const {
46.234 - return dims_;
46.235 - }
46.236 - Expression *initializer() const {
46.237 - return initializer_;
46.238 - }
46.239 - void setSymbol(VariableSymbol *sym) {
46.240 - assert(!sym_);
46.241 - sym_ = sym;
46.242 - }
46.243 - VariableSymbol *sym() const {
46.244 - return sym_;
46.245 - }
46.246 - const SourcePosition &pos() const {
46.247 - return pos_;
46.248 - }
46.249 -};
46.250 -
46.251 -class NameProxy : public Expression
46.252 -{
46.253 - ScopedRoot<String> name_;
46.254 - Symbol *binding_;
46.255 -
46.256 - public:
46.257 - NameProxy(const SourcePosition &pos, Handle<String> name)
46.258 - : Expression(pos),
46.259 - name_(name),
46.260 - binding_(NULL)
46.261 - {
46.262 - }
46.263 -
46.264 - DECLARE_NODE(NameProxy);
46.265 -
46.266 - Handle<String> name() const {
46.267 - return name_;
46.268 - }
46.269 - Symbol *sym() const {
46.270 - return binding_;
46.271 - }
46.272 - void bind(Symbol *sym) {
46.273 - binding_ = sym;
46.274 - }
46.275 -};
46.276 -
46.277 -class BooleanLiteral : public Expression
46.278 -{
46.279 - TokenKind token_;
46.280 -
46.281 - public:
46.282 - BooleanLiteral(const SourcePosition &pos, TokenKind token)
46.283 - : Expression(pos),
46.284 - token_(token)
46.285 - {
46.286 - }
46.287 -
46.288 - DECLARE_NODE(BooleanLiteral);
46.289 - TokenKind token() const {
46.290 - return token_;
46.291 - }
46.292 -};
46.293 -
46.294 -class IntegerLiteral : public Expression
46.295 -{
46.296 - int value_;
46.297 -
46.298 - public:
46.299 - IntegerLiteral(const SourcePosition &pos, int value)
46.300 - : Expression(pos),
46.301 - value_(value)
46.302 - {
46.303 - }
46.304 -
46.305 - DECLARE_NODE(IntegerLiteral);
46.306 -
46.307 - int value() const {
46.308 - return value_;
46.309 - }
46.310 -};
46.311 -
46.312 -class FloatLiteral : public Expression
46.313 -{
46.314 - double value_;
46.315 -
46.316 - public:
46.317 - FloatLiteral(const SourcePosition &pos, double value)
46.318 - : Expression(pos),
46.319 - value_(value)
46.320 - {
46.321 - }
46.322 -
46.323 - DECLARE_NODE(FloatLiteral);
46.324 -
46.325 - double value() const {
46.326 - return value_;
46.327 - }
46.328 -};
46.329 -
46.330 -class StringLiteral : public Expression
46.331 -{
46.332 - ScopedRoot<String> string_;
46.333 -
46.334 - public:
46.335 - StringLiteral(const SourcePosition &pos, String *string)
46.336 - : Expression(pos),
46.337 - string_(string)
46.338 - {
46.339 - }
46.340 -
46.341 - DECLARE_NODE(StringLiteral);
46.342 -
46.343 - String *string() const {
46.344 - return string_;
46.345 - }
46.346 -};
46.347 -
46.348 -class ArrayLiteral : public Expression
46.349 -{
46.350 - TokenKind token_;
46.351 - ExpressionList *expressions_;
46.352 -
46.353 - public:
46.354 - ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
46.355 - : Expression(pos),
46.356 - token_(token),
46.357 - expressions_(expressions)
46.358 - {
46.359 - }
46.360 -
46.361 - DECLARE_NODE(ArrayLiteral);
46.362 -
46.363 - TokenKind token() const {
46.364 - return token_;
46.365 - }
46.366 - ExpressionList *expressions() const {
46.367 - return expressions_;
46.368 - }
46.369 - bool isFixed() const {
46.370 - return token_ == TOK_LBRACE;
46.371 - }
46.372 -};
46.373 -
46.374 -class UnaryExpression : public Expression
46.375 -{
46.376 - Expression *expression_;
46.377 - TokenKind token_;
46.378 - NameProxy *tag_;
46.379 -
46.380 - public:
46.381 - UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
46.382 - : Expression(pos),
46.383 - expression_(expr),
46.384 - token_(token),
46.385 - tag_(NULL)
46.386 - {
46.387 - }
46.388 -
46.389 - UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
46.390 - NameProxy *tag)
46.391 - : Expression(pos),
46.392 - expression_(expr),
46.393 - token_(token),
46.394 - tag_(tag)
46.395 - {
46.396 - }
46.397 -
46.398 - DECLARE_NODE(UnaryExpression);
46.399 -
46.400 - Expression *expression() const {
46.401 - return expression_;
46.402 - }
46.403 - TokenKind token() const {
46.404 - return token_;
46.405 - }
46.406 - NameProxy *tag() const {
46.407 - return tag_;
46.408 - }
46.409 -};
46.410 -
46.411 -class BinaryExpression : public Expression
46.412 -{
46.413 - Expression *left_;
46.414 - Expression *right_;
46.415 - TokenKind token_;
46.416 -
46.417 - public:
46.418 - BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
46.419 - : Expression(pos),
46.420 - left_(left),
46.421 - right_(right),
46.422 - token_(token)
46.423 - {
46.424 - }
46.425 -
46.426 - DECLARE_NODE(BinaryExpression);
46.427 -
46.428 - Expression *left() const {
46.429 - return left_;
46.430 - }
46.431 - Expression *right() const {
46.432 - return right_;
46.433 - }
46.434 - TokenKind token() const {
46.435 - return token_;
46.436 - }
46.437 -};
46.438 -
46.439 -class TernaryExpression : public Expression
46.440 -{
46.441 - Expression *condition_;
46.442 - Expression *left_;
46.443 - Expression *right_;
46.444 -
46.445 - public:
46.446 - TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
46.447 - : Expression(pos),
46.448 - condition_(condition),
46.449 - left_(left),
46.450 - right_(right)
46.451 - {
46.452 - }
46.453 -
46.454 - DECLARE_NODE(TernaryExpression);
46.455 -
46.456 - Expression *condition() const {
46.457 - return condition_;
46.458 - }
46.459 - Expression *left() const {
46.460 - return left_;
46.461 - }
46.462 - Expression *right() const {
46.463 - return right_;
46.464 - }
46.465 -};
46.466 -
46.467 -class IndexExpression : public Expression
46.468 -{
46.469 - Expression *left_;
46.470 - Expression *right_;
46.471 -
46.472 - public:
46.473 - IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
46.474 - : Expression(pos),
46.475 - left_(left),
46.476 - right_(right)
46.477 - {
46.478 - }
46.479 -
46.480 - DECLARE_NODE(IndexExpression);
46.481 -
46.482 - Expression *left() const {
46.483 - return left_;
46.484 - }
46.485 - Expression *right() const {
46.486 - return right_;
46.487 - }
46.488 -};
46.489 -
46.490 -class FieldExpression : public Expression
46.491 -{
46.492 - Expression *left_;
46.493 - ScopedRoot<String> field_;
46.494 -
46.495 - public:
46.496 - FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
46.497 - : Expression(pos),
46.498 - left_(left),
46.499 - field_(field)
46.500 - {
46.501 - }
46.502 -
46.503 - DECLARE_NODE(FieldExpression);
46.504 -
46.505 - Expression *left() const {
46.506 - return left_;
46.507 - }
46.508 - Handle<String> field() const {
46.509 - return field_;
46.510 - }
46.511 -};
46.512 -
46.513 -class CallExpression : public Expression
46.514 -{
46.515 - Expression *callee_;
46.516 - ExpressionList *arguments_;
46.517 -
46.518 - public:
46.519 - CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
46.520 - : Expression(pos),
46.521 - callee_(callee),
46.522 - arguments_(arguments)
46.523 - {
46.524 - }
46.525 -
46.526 - DECLARE_NODE(CallExpression);
46.527 -
46.528 - Expression *callee() const {
46.529 - return callee_;
46.530 - }
46.531 - ExpressionList *arguments() const {
46.532 - return arguments_;
46.533 - }
46.534 -};
46.535 -
46.536 -class ForStatement : public Statement
46.537 -{
46.538 - Statement *initialization_;
46.539 - Expression *condition_;
46.540 - Statement *update_;
46.541 - Statement *body_;
46.542 - Scope *scope_;
46.543 -
46.544 - public:
46.545 - ForStatement(const SourcePosition &pos, Statement *initialization,
46.546 - Expression *condition, Statement *update, Statement *body)
46.547 - : Statement(pos),
46.548 - initialization_(initialization),
46.549 - condition_(condition),
46.550 - update_(update),
46.551 - body_(body),
46.552 - scope_(NULL)
46.553 - {
46.554 - }
46.555 -
46.556 - DECLARE_NODE(ForStatement);
46.557 -
46.558 - Statement *initialization() const {
46.559 - return initialization_;
46.560 - }
46.561 - Expression *condition() const {
46.562 - return condition_;
46.563 - }
46.564 - Statement *update() const {
46.565 - return update_;
46.566 - }
46.567 - Statement *body() const {
46.568 - return body_;
46.569 - }
46.570 - Scope *scope() const {
46.571 - return scope_;
46.572 - }
46.573 - void setScope(Scope *scope) {
46.574 - scope_ = scope;
46.575 - }
46.576 -};
46.577 -
46.578 -class WhileStatement : public Statement
46.579 -{
46.580 - TokenKind token_;
46.581 - Expression *condition_;
46.582 - Statement *body_;
46.583 -
46.584 - public:
46.585 - WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
46.586 - : Statement(pos),
46.587 - token_(kind),
46.588 - condition_(condition),
46.589 - body_(body)
46.590 - {
46.591 - }
46.592 -
46.593 - DECLARE_NODE(WhileStatement);
46.594 -
46.595 - TokenKind token() const {
46.596 - return token_;
46.597 - }
46.598 - Expression *condition() const {
46.599 - return condition_;
46.600 - }
46.601 - Statement *body() const {
46.602 - return body_;
46.603 - }
46.604 -};
46.605 -
46.606 -class ReturnStatement : public Statement
46.607 -{
46.608 - Expression *expression_;
46.609 -
46.610 - public:
46.611 - ReturnStatement(const SourcePosition &pos, Expression *expression)
46.612 - : Statement(pos),
46.613 - expression_(expression)
46.614 - {
46.615 - }
46.616 -
46.617 - DECLARE_NODE(ReturnStatement);
46.618 -
46.619 - Expression *expression() const {
46.620 - return expression_;
46.621 - }
46.622 -};
46.623 -
46.624 -class BreakStatement : public Statement
46.625 -{
46.626 - public:
46.627 - BreakStatement(const SourcePosition &pos)
46.628 - : Statement(pos)
46.629 - {
46.630 - }
46.631 -
46.632 - DECLARE_NODE(BreakStatement);
46.633 -};
46.634 -
46.635 -class ContinueStatement : public Statement
46.636 -{
46.637 - public:
46.638 - ContinueStatement(const SourcePosition &pos)
46.639 - : Statement(pos)
46.640 - {
46.641 - }
46.642 -
46.643 - DECLARE_NODE(ContinueStatement);
46.644 -};
46.645 -
46.646 -class Assignment : public Expression
46.647 -{
46.648 - TokenKind token_;
46.649 - Expression *lvalue_;
46.650 - Expression *expression_;
46.651 -
46.652 - public:
46.653 - Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
46.654 - : Expression(pos),
46.655 - token_(token),
46.656 - lvalue_(left),
46.657 - expression_(right)
46.658 - {
46.659 - }
46.660 -
46.661 - DECLARE_NODE(Assignment);
46.662 -
46.663 - TokenKind token() const {
46.664 - return token_;
46.665 - }
46.666 - Expression *lvalue() const {
46.667 - return lvalue_;
46.668 - }
46.669 - Expression *expression() const {
46.670 - return expression_;
46.671 - }
46.672 -};
46.673 -
46.674 -class ExpressionStatement : public Statement
46.675 -{
46.676 - Expression *expression_;
46.677 -
46.678 - public:
46.679 - ExpressionStatement(Expression *expression)
46.680 - : Statement(expression->pos()),
46.681 - expression_(expression)
46.682 - {
46.683 - }
46.684 -
46.685 - DECLARE_NODE(ExpressionStatement);
46.686 -
46.687 - Expression *expression() const {
46.688 - return expression_;
46.689 - }
46.690 -};
46.691 -
46.692 -class BlockStatement : public Statement
46.693 -{
46.694 - StatementList *statements_;
46.695 - Scope *scope_;
46.696 - TokenKind type_;
46.697 -
46.698 - public:
46.699 - BlockStatement(const SourcePosition &pos, StatementList *statements, TokenKind kind)
46.700 - : Statement(pos),
46.701 - statements_(statements),
46.702 - scope_(NULL),
46.703 - type_(kind)
46.704 - {
46.705 - }
46.706 -
46.707 - DECLARE_NODE(BlockStatement);
46.708 -
46.709 - StatementList *statements() const {
46.710 - return statements_;
46.711 - }
46.712 - Scope *scope() const {
46.713 - return scope_;
46.714 - }
46.715 - void setScope(Scope *scope) {
46.716 - scope_ = scope;
46.717 - }
46.718 - TokenKind type() const {
46.719 - return type_;
46.720 - }
46.721 -};
46.722 -
46.723 -typedef PoolList<Parameter *> ParameterList;
46.724 -
46.725 -class FunctionSignature
46.726 -{
46.727 - public:
46.728 - FunctionSignature(Expression *returnType, ParameterList *parameters, bool variadic)
46.729 - : returnType_(returnType),
46.730 - parameters_(parameters),
46.731 - variadic_(variadic)
46.732 - {
46.733 - }
46.734 -
46.735 - Expression *returnType() const {
46.736 - return returnType_;
46.737 - }
46.738 - ParameterList *parameters() const {
46.739 - return parameters_;
46.740 - }
46.741 - bool variadic() const {
46.742 - return variadic_;
46.743 - }
46.744 -
46.745 - private:
46.746 - Expression *returnType_;
46.747 - ParameterList *parameters_;
46.748 - bool variadic_;
46.749 -};
46.750 -
46.751 -class FunctionTypeStatement : public Statement
46.752 -{
46.753 - public:
46.754 - FunctionTypeStatement(const SourcePosition &pos, Handle<String> name, const FunctionSignature &signature)
46.755 - : Statement(pos),
46.756 - name_(name),
46.757 - signature_(signature)
46.758 - {
46.759 - }
46.760 -
46.761 - DECLARE_NODE(FunctionTypeStatement);
46.762 -
46.763 - Handle<String> name() const {
46.764 - return name_;
46.765 - }
46.766 - const FunctionSignature &signature() const {
46.767 - return signature_;
46.768 - }
46.769 -
46.770 - private:
46.771 - ScopedRoot<String> name_;
46.772 - FunctionSignature signature_;
46.773 -
46.774 -};
46.775 -
46.776 -class FunctionStatement : public Statement
46.777 -{
46.778 - ScopedRoot<String> name_;
46.779 - TokenKind kind_;
46.780 - Statement *body_;
46.781 - FunctionSignature signature_;
46.782 - bool explicitReturn_;
46.783 - FunctionSymbol *sym_;
46.784 - Scope *argScope_;
46.785 - Scope *varScope_;
46.786 -
46.787 - public:
46.788 - FunctionStatement(const SourcePosition &pos, Handle<String> name, TokenKind kind,
46.789 - Statement *body, const FunctionSignature &signature, bool explicitReturn)
46.790 - : Statement(pos),
46.791 - name_(name),
46.792 - kind_(kind),
46.793 - body_(body),
46.794 - signature_(signature),
46.795 - explicitReturn_(explicitReturn),
46.796 - sym_(NULL),
46.797 - argScope_(NULL),
46.798 - varScope_(NULL)
46.799 - {
46.800 - }
46.801 -
46.802 - DECLARE_NODE(FunctionStatement);
46.803 -
46.804 - Handle<String> name() const {
46.805 - return name_;
46.806 - }
46.807 - Statement *body() const {
46.808 - return body_;
46.809 - }
46.810 - const FunctionSignature &signature() {
46.811 - return signature_;
46.812 - }
46.813 - bool hasExplicitReturn() const {
46.814 - return explicitReturn_;
46.815 - }
46.816 - TokenKind token() const {
46.817 - return kind_;
46.818 - }
46.819 - void setSymbol(FunctionSymbol *sym) {
46.820 - assert(!sym_);
46.821 - sym_ = sym;
46.822 - }
46.823 - FunctionSymbol *sym() const {
46.824 - return sym_;
46.825 - }
46.826 - void setScopes(Scope *argScope, Scope *varScope) {
46.827 - argScope_ = argScope;
46.828 - varScope_ = varScope;
46.829 - }
46.830 - Scope *argScope() const {
46.831 - return argScope_;
46.832 - }
46.833 - Scope *varScope() const {
46.834 - return varScope_;
46.835 - }
46.836 -};
46.837 -
46.838 -class IfStatement : public Statement
46.839 -{
46.840 - Expression *condition_;
46.841 - Statement *ifTrue_;
46.842 - Statement *ifFalse_;
46.843 -
46.844 - public:
46.845 - IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
46.846 - : Statement(pos),
46.847 - condition_(condition),
46.848 - ifTrue_(ifTrue),
46.849 - ifFalse_(NULL)
46.850 - {
46.851 - }
46.852 -
46.853 - DECLARE_NODE(IfStatement);
46.854 -
46.855 - Expression *condition() const {
46.856 - return condition_;
46.857 - }
46.858 - Statement *ifTrue() const {
46.859 - return ifTrue_;
46.860 - }
46.861 - Statement *ifFalse() const {
46.862 - return ifFalse_;
46.863 - }
46.864 - void setIfFalse(Statement *ifFalse) {
46.865 - ifFalse_ = ifFalse;
46.866 - }
46.867 -};
46.868 -
46.869 -class EnumStatement : public Statement
46.870 -{
46.871 - ScopedRoot<String> name_;
46.872 - TypeSymbol *sym_;
46.873 -
46.874 - public:
46.875 - struct Entry {
46.876 - ScopedRoot<String> name;
46.877 - Expression *expr;
46.878 - SourcePosition pos;
46.879 - ConstantSymbol *sym;
46.880 -
46.881 - Entry(Handle<String> name, Expression *expr, const SourcePosition &pos)
46.882 - : name(name),
46.883 - expr(expr),
46.884 - pos(pos),
46.885 - sym(NULL)
46.886 - {
46.887 - }
46.888 - };
46.889 -
46.890 - typedef PoolList<Entry> EntryList;
46.891 -
46.892 - public:
46.893 - EnumStatement(const SourcePosition &pos, TokenKind visibility, Handle<String> name, EntryList *entries)
46.894 - : Statement(pos),
46.895 - name_(name),
46.896 - sym_(NULL),
46.897 - entries_(entries),
46.898 - visibility_(visibility)
46.899 - {
46.900 - }
46.901 -
46.902 - DECLARE_NODE(EnumStatement);
46.903 -
46.904 - Handle<String> name() const {
46.905 - return name_;
46.906 - }
46.907 - EntryList *entries() const {
46.908 - return entries_;
46.909 - }
46.910 - void setSymbol(TypeSymbol *sym) {
46.911 - assert(!sym_);
46.912 - sym_ = sym;
46.913 - }
46.914 - TypeSymbol *sym() const {
46.915 - return sym_;
46.916 - }
46.917 - TokenKind visibility() const {
46.918 - return visibility_;
46.919 - }
46.920 -
46.921 - private:
46.922 - EntryList *entries_;
46.923 - TokenKind visibility_;
46.924 -};
46.925 -
46.926 -class IncDecExpression : public Expression
46.927 -{
46.928 - TokenKind token_;
46.929 - Expression *expression_;
46.930 - bool postfix_;
46.931 -
46.932 - public:
46.933 - IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
46.934 - : Expression(pos),
46.935 - token_(token),
46.936 - expression_(expression),
46.937 - postfix_(postfix)
46.938 - {
46.939 - }
46.940 -
46.941 - DECLARE_NODE(IncDecExpression);
46.942 -
46.943 - TokenKind token() const {
46.944 - return token_;
46.945 - }
46.946 - Expression *expression() const {
46.947 - return expression_;
46.948 - }
46.949 - bool postfix() const {
46.950 - return postfix_;
46.951 - }
46.952 -};
46.953 -
46.954 -class Case : public PoolObject
46.955 -{
46.956 - public:
46.957 - Case(Expression *expression, ExpressionList *others, Statement *statement)
46.958 - : expression_(expression),
46.959 - others_(others),
46.960 - statement_(statement)
46.961 - {
46.962 - }
46.963 -
46.964 - Expression *expression() const {
46.965 - return expression_;
46.966 - }
46.967 - PoolList<Expression *> *others() const {
46.968 - return others_;
46.969 - }
46.970 - Statement *statement() const {
46.971 - return statement_;
46.972 - }
46.973 -
46.974 - private:
46.975 - Expression *expression_;
46.976 - PoolList <Expression *> *others_;
46.977 - Statement *statement_;
46.978 -};
46.979 -
46.980 -struct CaseValue
46.981 -{
46.982 - BoxedPrimitive box;
46.983 - size_t statement;
46.984 -
46.985 - CaseValue(size_t statement)
46.986 - : statement(statement)
46.987 - {
46.988 - }
46.989 -};
46.990 -
46.991 -typedef PoolList<CaseValue> CaseValueList;
46.992 -
46.993 -class SwitchStatement : public Statement
46.994 -{
46.995 - public:
46.996 - SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
46.997 - Statement *def)
46.998 - : Statement(pos),
46.999 - expression_(expression),
46.1000 - cases_(cases),
46.1001 - default_(def),
46.1002 - table_(NULL)
46.1003 - {
46.1004 - }
46.1005 -
46.1006 - DECLARE_NODE(SwitchStatement);
46.1007 -
46.1008 - Expression *expression() const {
46.1009 - return expression_;
46.1010 - }
46.1011 - PoolList<Case *> *cases() const {
46.1012 - return cases_;
46.1013 - }
46.1014 - Statement *defaultCase() const {
46.1015 - return default_;
46.1016 - }
46.1017 - void setCaseValueList(CaseValueList *list) {
46.1018 - table_ = list;
46.1019 - }
46.1020 - CaseValueList *caseValueList() const {
46.1021 - return table_;
46.1022 - }
46.1023 -
46.1024 - private:
46.1025 - Expression *expression_;
46.1026 - PoolList<Case *> *cases_;
46.1027 - Statement *default_;
46.1028 - CaseValueList *table_;
46.1029 -};
46.1030 -
46.1031 -class StructureStatement : public Statement
46.1032 -{
46.1033 - public:
46.1034 - class Field : public PoolObject
46.1035 - {
46.1036 - SourcePosition pos_;
46.1037 - Expression *type_;
46.1038 - ScopedRoot<String> name_;
46.1039 -
46.1040 - public:
46.1041 - Field(const SourcePosition &pos,
46.1042 - Expression *type,
46.1043 - Handle<String> name)
46.1044 - : pos_(pos),
46.1045 - type_(type),
46.1046 - name_(name)
46.1047 - {
46.1048 - }
46.1049 -
46.1050 - const SourcePosition &pos() const {
46.1051 - return pos_;
46.1052 - }
46.1053 - Handle<String> name() const {
46.1054 - return name_;
46.1055 - }
46.1056 - Expression *type() const {
46.1057 - return type_;
46.1058 - }
46.1059 - };
46.1060 -
46.1061 - typedef PoolList<StructureStatement::Field *> FieldList;
46.1062 -
46.1063 - public:
46.1064 - StructureStatement(const SourcePosition &pos, Handle<String> name, FieldList *fields)
46.1065 - : Statement(pos),
46.1066 - name_(name),
46.1067 - fields_(fields),
46.1068 - sym_(NULL)
46.1069 - {
46.1070 - }
46.1071 -
46.1072 - DECLARE_NODE(StructureStatement);
46.1073 -
46.1074 - FieldList *fields() const {
46.1075 - return fields_;
46.1076 - }
46.1077 - Handle<String> name() const {
46.1078 - return name_;
46.1079 - }
46.1080 - void setSymbol(TypeSymbol *sym) {
46.1081 - assert(!sym_);
46.1082 - sym_ = sym;
46.1083 - }
46.1084 - TypeSymbol *sym() const {
46.1085 - return sym_;
46.1086 - }
46.1087 -
46.1088 - private:
46.1089 - ScopedRoot<String> name_;
46.1090 - FieldList *fields_;
46.1091 - TypeSymbol *sym_;
46.1092 -};
46.1093 -
46.1094 -typedef PoolList<ScopedRoot<String> *> NameList;
46.1095 -
46.1096 -class ImportStatement : public Statement
46.1097 -{
46.1098 - public:
46.1099 - ImportStatement(const SourcePosition &pos, PathComponent *path, NameList *names)
46.1100 - : Statement(pos),
46.1101 - path_(path),
46.1102 - names_(names)
46.1103 - {
46.1104 - }
46.1105 -
46.1106 - DECLARE_NODE(ImportStatement);
46.1107 -
46.1108 - PathComponent *path() const {
46.1109 - return path_;
46.1110 - }
46.1111 - void setSource(Importable *source) {
46.1112 - source_ = source;
46.1113 - }
46.1114 - Handle<Importable> source() {
46.1115 - return source_;
46.1116 - }
46.1117 - unsigned importIndex() const {
46.1118 - return importIndex_;
46.1119 - }
46.1120 - void setImportIndex(unsigned index) {
46.1121 - importIndex_ = index;
46.1122 - }
46.1123 - NameList *names() const {
46.1124 - return names_;
46.1125 - }
46.1126 -
46.1127 - bool importAllNames() const {
46.1128 - return names_ && names_->empty();
46.1129 - }
46.1130 -
46.1131 - private:
46.1132 - PathComponent *path_;
46.1133 - ScopedRoot<Importable> source_;
46.1134 - unsigned importIndex_;
46.1135 - NameList *names_;
46.1136 -};
46.1137 -
46.1138 -typedef StructureStatement::FieldList FieldList;
46.1139 -typedef PoolList<NameProxy *> NameProxyList;
46.1140 -
46.1141 -#undef DECLARE_NODE
46.1142 -
46.1143 -class ParseTree : public PoolObject
46.1144 -{
46.1145 - StatementList *statements_;
46.1146 - NameProxyList *unbound_;
46.1147 - PoolList<ImportStatement *> *imports_;
46.1148 -
46.1149 - public:
46.1150 - ParseTree(StatementList *statements, NameProxyList *unbound, PoolList<ImportStatement *> *imports)
46.1151 - : statements_(statements),
46.1152 - unbound_(unbound),
46.1153 - imports_(imports)
46.1154 - {
46.1155 - }
46.1156 -
46.1157 - void dump(FILE *fp);
46.1158 -
46.1159 - StatementList *statements() const {
46.1160 - return statements_;
46.1161 - }
46.1162 - NameProxyList *unbound() const {
46.1163 - return unbound_;
46.1164 - }
46.1165 - PoolList<ImportStatement *> *imports() const {
46.1166 - return imports_;
46.1167 - }
46.1168 -};
46.1169 -
46.1170 -}
46.1171 -
46.1172 -#endif // _include_sourcepawn_ast_h_
46.1173 +/* vim: set ts=4 sw=4 tw=99 et:
46.1174 + *
46.1175 + * Copyright (C) 2012 David Anderson
46.1176 + *
46.1177 + * This file is part of SourcePawn.
46.1178 + *
46.1179 + * SourcePawn is free software: you can redistribute it and/or modify it under
46.1180 + * the terms of the GNU General Public License as published by the Free
46.1181 + * Software Foundation, either version 3 of the License, or (at your option)
46.1182 + * any later version.
46.1183 + *
46.1184 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
46.1185 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
46.1186 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
46.1187 + *
46.1188 + * You should have received a copy of the GNU General Public License along with
46.1189 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
46.1190 + */
46.1191 +#ifndef _include_sourcepawn_ast_h_
46.1192 +#define _include_sourcepawn_ast_h_
46.1193 +
46.1194 +#include "../PoolAllocator.h"
46.1195 +#include "../Vector.h"
46.1196 +#include "Token.h"
46.1197 +#include "NameBinding.h"
46.1198 +#include "Symbols.h"
46.1199 +
46.1200 +namespace ke {
46.1201 +
46.1202 +class Scope;
46.1203 +class Importable;
46.1204 +struct PathComponent;
46.1205 +
46.1206 +#define ASTKINDS(_) \
46.1207 + _(VariableDeclaration) \
46.1208 + _(ForStatement) \
46.1209 + _(ReturnStatement) \
46.1210 + _(IntegerLiteral) \
46.1211 + _(FloatLiteral) \
46.1212 + _(StringLiteral) \
46.1213 + _(BinaryExpression) \
46.1214 + _(BlockStatement) \
46.1215 + _(Assignment) \
46.1216 + _(NameProxy) \
46.1217 + _(ExpressionStatement) \
46.1218 + _(FunctionStatement) \
46.1219 + _(CallExpression) \
46.1220 + _(IfStatement) \
46.1221 + _(IndexExpression) \
46.1222 + _(FieldExpression) \
46.1223 + _(EnumStatement) \
46.1224 + _(WhileStatement) \
46.1225 + _(BreakStatement) \
46.1226 + _(ContinueStatement) \
46.1227 + _(FunctionTypeStatement) \
46.1228 + _(IncDecExpression) \
46.1229 + _(UnaryExpression) \
46.1230 + _(TernaryExpression) \
46.1231 + _(BooleanLiteral) \
46.1232 + _(StructureStatement) \
46.1233 + _(SwitchStatement) \
46.1234 + _(ArrayLiteral) \
46.1235 + _(ImportStatement)
46.1236 +
46.1237 +// Forward declarations.
46.1238 +#define _(name) class name;
46.1239 +ASTKINDS(_)
46.1240 +#undef _
46.1241 +
46.1242 +class AstVisitor;
46.1243 +
46.1244 +// Interface for AST nodes.
46.1245 +class AstNode : public PoolObject
46.1246 +{
46.1247 + SourcePosition pos_;
46.1248 +
46.1249 + public:
46.1250 + enum Kind {
46.1251 +# define _(name) k##name,
46.1252 + ASTKINDS(_)
46.1253 +# undef _
46.1254 + AstKind_Invalid
46.1255 + };
46.1256 +
46.1257 + AstNode(const SourcePosition &pos)
46.1258 + : pos_(pos)
46.1259 + {
46.1260 + }
46.1261 +
46.1262 + virtual Kind kind() const = 0;
46.1263 +
46.1264 +#define _(name) bool is##name() { return kind() == k##name; } \
46.1265 + name *to##name() { assert(is##name()); return (name *)this; } \
46.1266 + name *as##name() { if (!is##name()) return NULL; return to##name(); }
46.1267 + ASTKINDS(_)
46.1268 +#undef _
46.1269 +
46.1270 + virtual void accept(AstVisitor *visitor) = 0;
46.1271 +
46.1272 + const SourcePosition &pos() const {
46.1273 + return pos_;
46.1274 + }
46.1275 +};
46.1276 +
46.1277 +#define DECLARE_NODE(type) \
46.1278 + Kind kind() const { \
46.1279 + return k##type; \
46.1280 + } \
46.1281 + void accept(AstVisitor *visitor) { \
46.1282 + visitor->visit##type(this); \
46.1283 + }
46.1284 +
46.1285 +class AstVisitor
46.1286 +{
46.1287 + public:
46.1288 +#define _(name) virtual void visit##name(name *node) { assert(false); }
46.1289 + ASTKINDS(_)
46.1290 +#undef _
46.1291 +};
46.1292 +
46.1293 +class Statement : public AstNode
46.1294 +{
46.1295 + public:
46.1296 + Statement(const SourcePosition &pos)
46.1297 + : AstNode(pos)
46.1298 + {
46.1299 + }
46.1300 +};
46.1301 +
46.1302 +class Expression : public AstNode
46.1303 +{
46.1304 + public:
46.1305 + Expression(const SourcePosition &pos)
46.1306 + : AstNode(pos)
46.1307 + {
46.1308 + }
46.1309 +};
46.1310 +
46.1311 +typedef PoolList<Statement *> StatementList;
46.1312 +typedef PoolList<Expression *> ExpressionList;
46.1313 +
46.1314 +class VariableDeclaration : public Statement
46.1315 +{
46.1316 + TypeQualifiers qual_;
46.1317 + ScopedRoot<String> name_;
46.1318 + Expression *initialization_;
46.1319 + ExpressionList *dims_;
46.1320 + Expression *type_;
46.1321 + VariableSymbol *sym_;
46.1322 +
46.1323 + public:
46.1324 + VariableDeclaration(const SourcePosition &pos, TypeQualifiers qual, Handle<String> name,
46.1325 + Expression *type, ExpressionList *dims, Expression *initialization)
46.1326 + : Statement(pos),
46.1327 + qual_(qual),
46.1328 + name_(name),
46.1329 + initialization_(initialization),
46.1330 + dims_(dims),
46.1331 + type_(type),
46.1332 + sym_(NULL)
46.1333 + {
46.1334 + }
46.1335 +
46.1336 + DECLARE_NODE(VariableDeclaration);
46.1337 +
46.1338 + Expression *initialization() const {
46.1339 + return initialization_;
46.1340 + }
46.1341 + Handle<String> name() {
46.1342 + return name_;
46.1343 + }
46.1344 + Expression *declType() const {
46.1345 + return type_;
46.1346 + }
46.1347 + void setSymbol(VariableSymbol *sym) {
46.1348 + assert(!sym_);
46.1349 + sym_ = sym;
46.1350 + }
46.1351 + VariableSymbol *sym() const {
46.1352 + return sym_;
46.1353 + }
46.1354 + Expression *type() const {
46.1355 + return type_;
46.1356 + }
46.1357 + ExpressionList *dims() const {
46.1358 + return dims_;
46.1359 + }
46.1360 + TypeQualifiers quals() const {
46.1361 + return qual_;
46.1362 + }
46.1363 +};
46.1364 +
46.1365 +class Parameter : public PoolObject
46.1366 +{
46.1367 + ScopedRoot<String> name_;
46.1368 + Expression *type_;
46.1369 + bool reference_;
46.1370 + Expression *initializer_;
46.1371 + VariableSymbol *sym_;
46.1372 + SourcePosition pos_;
46.1373 + ExpressionList *dims_;
46.1374 + TypeQualifiers quals_;
46.1375 +
46.1376 + public:
46.1377 + Parameter(Handle<String> name, Expression *type, bool reference, TypeQualifiers quals,
46.1378 + ExpressionList *dims, Expression *initializer, const SourcePosition &pos)
46.1379 + : name_(name),
46.1380 + type_(type),
46.1381 + reference_(reference),
46.1382 + initializer_(initializer),
46.1383 + sym_(NULL),
46.1384 + pos_(pos),
46.1385 + dims_(dims),
46.1386 + quals_(quals)
46.1387 + {
46.1388 + }
46.1389 +
46.1390 + Expression *type() const {
46.1391 + return type_;
46.1392 + }
46.1393 + Handle<String> name() const {
46.1394 + return name_;
46.1395 + }
46.1396 + bool reference() const {
46.1397 + return reference_;
46.1398 + }
46.1399 + TypeQualifiers quals() const {
46.1400 + return quals_;
46.1401 + }
46.1402 + ExpressionList *dims() const {
46.1403 + return dims_;
46.1404 + }
46.1405 + Expression *initializer() const {
46.1406 + return initializer_;
46.1407 + }
46.1408 + void setSymbol(VariableSymbol *sym) {
46.1409 + assert(!sym_);
46.1410 + sym_ = sym;
46.1411 + }
46.1412 + VariableSymbol *sym() const {
46.1413 + return sym_;
46.1414 + }
46.1415 + const SourcePosition &pos() const {
46.1416 + return pos_;
46.1417 + }
46.1418 +};
46.1419 +
46.1420 +class NameProxy : public Expression
46.1421 +{
46.1422 + ScopedRoot<String> name_;
46.1423 + Symbol *binding_;
46.1424 +
46.1425 + public:
46.1426 + NameProxy(const SourcePosition &pos, Handle<String> name)
46.1427 + : Expression(pos),
46.1428 + name_(name),
46.1429 + binding_(NULL)
46.1430 + {
46.1431 + }
46.1432 +
46.1433 + DECLARE_NODE(NameProxy);
46.1434 +
46.1435 + Handle<String> name() const {
46.1436 + return name_;
46.1437 + }
46.1438 + Symbol *sym() const {
46.1439 + return binding_;
46.1440 + }
46.1441 + void bind(Symbol *sym) {
46.1442 + binding_ = sym;
46.1443 + }
46.1444 +};
46.1445 +
46.1446 +class BooleanLiteral : public Expression
46.1447 +{
46.1448 + TokenKind token_;
46.1449 +
46.1450 + public:
46.1451 + BooleanLiteral(const SourcePosition &pos, TokenKind token)
46.1452 + : Expression(pos),
46.1453 + token_(token)
46.1454 + {
46.1455 + }
46.1456 +
46.1457 + DECLARE_NODE(BooleanLiteral);
46.1458 + TokenKind token() const {
46.1459 + return token_;
46.1460 + }
46.1461 +};
46.1462 +
46.1463 +class IntegerLiteral : public Expression
46.1464 +{
46.1465 + int value_;
46.1466 +
46.1467 + public:
46.1468 + IntegerLiteral(const SourcePosition &pos, int value)
46.1469 + : Expression(pos),
46.1470 + value_(value)
46.1471 + {
46.1472 + }
46.1473 +
46.1474 + DECLARE_NODE(IntegerLiteral);
46.1475 +
46.1476 + int value() const {
46.1477 + return value_;
46.1478 + }
46.1479 +};
46.1480 +
46.1481 +class FloatLiteral : public Expression
46.1482 +{
46.1483 + double value_;
46.1484 +
46.1485 + public:
46.1486 + FloatLiteral(const SourcePosition &pos, double value)
46.1487 + : Expression(pos),
46.1488 + value_(value)
46.1489 + {
46.1490 + }
46.1491 +
46.1492 + DECLARE_NODE(FloatLiteral);
46.1493 +
46.1494 + double value() const {
46.1495 + return value_;
46.1496 + }
46.1497 +};
46.1498 +
46.1499 +class StringLiteral : public Expression
46.1500 +{
46.1501 + ScopedRoot<String> string_;
46.1502 +
46.1503 + public:
46.1504 + StringLiteral(const SourcePosition &pos, String *string)
46.1505 + : Expression(pos),
46.1506 + string_(string)
46.1507 + {
46.1508 + }
46.1509 +
46.1510 + DECLARE_NODE(StringLiteral);
46.1511 +
46.1512 + String *string() const {
46.1513 + return string_;
46.1514 + }
46.1515 +};
46.1516 +
46.1517 +class ArrayLiteral : public Expression
46.1518 +{
46.1519 + TokenKind token_;
46.1520 + ExpressionList *expressions_;
46.1521 +
46.1522 + public:
46.1523 + ArrayLiteral(const SourcePosition &pos, TokenKind token, ExpressionList *expressions)
46.1524 + : Expression(pos),
46.1525 + token_(token),
46.1526 + expressions_(expressions)
46.1527 + {
46.1528 + }
46.1529 +
46.1530 + DECLARE_NODE(ArrayLiteral);
46.1531 +
46.1532 + TokenKind token() const {
46.1533 + return token_;
46.1534 + }
46.1535 + ExpressionList *expressions() const {
46.1536 + return expressions_;
46.1537 + }
46.1538 + bool isFixed() const {
46.1539 + return token_ == TOK_LBRACE;
46.1540 + }
46.1541 +};
46.1542 +
46.1543 +class UnaryExpression : public Expression
46.1544 +{
46.1545 + Expression *expression_;
46.1546 + TokenKind token_;
46.1547 + NameProxy *tag_;
46.1548 +
46.1549 + public:
46.1550 + UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr)
46.1551 + : Expression(pos),
46.1552 + expression_(expr),
46.1553 + token_(token),
46.1554 + tag_(NULL)
46.1555 + {
46.1556 + }
46.1557 +
46.1558 + UnaryExpression(const SourcePosition &pos, TokenKind token, Expression *expr,
46.1559 + NameProxy *tag)
46.1560 + : Expression(pos),
46.1561 + expression_(expr),
46.1562 + token_(token),
46.1563 + tag_(tag)
46.1564 + {
46.1565 + }
46.1566 +
46.1567 + DECLARE_NODE(UnaryExpression);
46.1568 +
46.1569 + Expression *expression() const {
46.1570 + return expression_;
46.1571 + }
46.1572 + TokenKind token() const {
46.1573 + return token_;
46.1574 + }
46.1575 + NameProxy *tag() const {
46.1576 + return tag_;
46.1577 + }
46.1578 +};
46.1579 +
46.1580 +class BinaryExpression : public Expression
46.1581 +{
46.1582 + Expression *left_;
46.1583 + Expression *right_;
46.1584 + TokenKind token_;
46.1585 +
46.1586 + public:
46.1587 + BinaryExpression(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
46.1588 + : Expression(pos),
46.1589 + left_(left),
46.1590 + right_(right),
46.1591 + token_(token)
46.1592 + {
46.1593 + }
46.1594 +
46.1595 + DECLARE_NODE(BinaryExpression);
46.1596 +
46.1597 + Expression *left() const {
46.1598 + return left_;
46.1599 + }
46.1600 + Expression *right() const {
46.1601 + return right_;
46.1602 + }
46.1603 + TokenKind token() const {
46.1604 + return token_;
46.1605 + }
46.1606 +};
46.1607 +
46.1608 +class TernaryExpression : public Expression
46.1609 +{
46.1610 + Expression *condition_;
46.1611 + Expression *left_;
46.1612 + Expression *right_;
46.1613 +
46.1614 + public:
46.1615 + TernaryExpression(const SourcePosition &pos, Expression *condition, Expression *left, Expression *right)
46.1616 + : Expression(pos),
46.1617 + condition_(condition),
46.1618 + left_(left),
46.1619 + right_(right)
46.1620 + {
46.1621 + }
46.1622 +
46.1623 + DECLARE_NODE(TernaryExpression);
46.1624 +
46.1625 + Expression *condition() const {
46.1626 + return condition_;
46.1627 + }
46.1628 + Expression *left() const {
46.1629 + return left_;
46.1630 + }
46.1631 + Expression *right() const {
46.1632 + return right_;
46.1633 + }
46.1634 +};
46.1635 +
46.1636 +class IndexExpression : public Expression
46.1637 +{
46.1638 + Expression *left_;
46.1639 + Expression *right_;
46.1640 +
46.1641 + public:
46.1642 + IndexExpression(const SourcePosition &pos, Expression *left, Expression *right)
46.1643 + : Expression(pos),
46.1644 + left_(left),
46.1645 + right_(right)
46.1646 + {
46.1647 + }
46.1648 +
46.1649 + DECLARE_NODE(IndexExpression);
46.1650 +
46.1651 + Expression *left() const {
46.1652 + return left_;
46.1653 + }
46.1654 + Expression *right() const {
46.1655 + return right_;
46.1656 + }
46.1657 +};
46.1658 +
46.1659 +class FieldExpression : public Expression
46.1660 +{
46.1661 + Expression *left_;
46.1662 + ScopedRoot<String> field_;
46.1663 +
46.1664 + public:
46.1665 + FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
46.1666 + : Expression(pos),
46.1667 + left_(left),
46.1668 + field_(field)
46.1669 + {
46.1670 + }
46.1671 +
46.1672 + DECLARE_NODE(FieldExpression);
46.1673 +
46.1674 + Expression *left() const {
46.1675 + return left_;
46.1676 + }
46.1677 + Handle<String> field() const {
46.1678 + return field_;
46.1679 + }
46.1680 +};
46.1681 +
46.1682 +class CallExpression : public Expression
46.1683 +{
46.1684 + Expression *callee_;
46.1685 + ExpressionList *arguments_;
46.1686 +
46.1687 + public:
46.1688 + CallExpression(const SourcePosition &pos, Expression *callee, ExpressionList *arguments)
46.1689 + : Expression(pos),
46.1690 + callee_(callee),
46.1691 + arguments_(arguments)
46.1692 + {
46.1693 + }
46.1694 +
46.1695 + DECLARE_NODE(CallExpression);
46.1696 +
46.1697 + Expression *callee() const {
46.1698 + return callee_;
46.1699 + }
46.1700 + ExpressionList *arguments() const {
46.1701 + return arguments_;
46.1702 + }
46.1703 +};
46.1704 +
46.1705 +class ForStatement : public Statement
46.1706 +{
46.1707 + Statement *initialization_;
46.1708 + Expression *condition_;
46.1709 + Statement *update_;
46.1710 + Statement *body_;
46.1711 + Scope *scope_;
46.1712 +
46.1713 + public:
46.1714 + ForStatement(const SourcePosition &pos, Statement *initialization,
46.1715 + Expression *condition, Statement *update, Statement *body)
46.1716 + : Statement(pos),
46.1717 + initialization_(initialization),
46.1718 + condition_(condition),
46.1719 + update_(update),
46.1720 + body_(body),
46.1721 + scope_(NULL)
46.1722 + {
46.1723 + }
46.1724 +
46.1725 + DECLARE_NODE(ForStatement);
46.1726 +
46.1727 + Statement *initialization() const {
46.1728 + return initialization_;
46.1729 + }
46.1730 + Expression *condition() const {
46.1731 + return condition_;
46.1732 + }
46.1733 + Statement *update() const {
46.1734 + return update_;
46.1735 + }
46.1736 + Statement *body() const {
46.1737 + return body_;
46.1738 + }
46.1739 + Scope *scope() const {
46.1740 + return scope_;
46.1741 + }
46.1742 + void setScope(Scope *scope) {
46.1743 + scope_ = scope;
46.1744 + }
46.1745 +};
46.1746 +
46.1747 +class WhileStatement : public Statement
46.1748 +{
46.1749 + TokenKind token_;
46.1750 + Expression *condition_;
46.1751 + Statement *body_;
46.1752 +
46.1753 + public:
46.1754 + WhileStatement(const SourcePosition &pos, TokenKind kind, Expression *condition, Statement *body)
46.1755 + : Statement(pos),
46.1756 + token_(kind),
46.1757 + condition_(condition),
46.1758 + body_(body)
46.1759 + {
46.1760 + }
46.1761 +
46.1762 + DECLARE_NODE(WhileStatement);
46.1763 +
46.1764 + TokenKind token() const {
46.1765 + return token_;
46.1766 + }
46.1767 + Expression *condition() const {
46.1768 + return condition_;
46.1769 + }
46.1770 + Statement *body() const {
46.1771 + return body_;
46.1772 + }
46.1773 +};
46.1774 +
46.1775 +class ReturnStatement : public Statement
46.1776 +{
46.1777 + Expression *expression_;
46.1778 +
46.1779 + public:
46.1780 + ReturnStatement(const SourcePosition &pos, Expression *expression)
46.1781 + : Statement(pos),
46.1782 + expression_(expression)
46.1783 + {
46.1784 + }
46.1785 +
46.1786 + DECLARE_NODE(ReturnStatement);
46.1787 +
46.1788 + Expression *expression() const {
46.1789 + return expression_;
46.1790 + }
46.1791 +};
46.1792 +
46.1793 +class BreakStatement : public Statement
46.1794 +{
46.1795 + public:
46.1796 + BreakStatement(const SourcePosition &pos)
46.1797 + : Statement(pos)
46.1798 + {
46.1799 + }
46.1800 +
46.1801 + DECLARE_NODE(BreakStatement);
46.1802 +};
46.1803 +
46.1804 +class ContinueStatement : public Statement
46.1805 +{
46.1806 + public:
46.1807 + ContinueStatement(const SourcePosition &pos)
46.1808 + : Statement(pos)
46.1809 + {
46.1810 + }
46.1811 +
46.1812 + DECLARE_NODE(ContinueStatement);
46.1813 +};
46.1814 +
46.1815 +class Assignment : public Expression
46.1816 +{
46.1817 + TokenKind token_;
46.1818 + Expression *lvalue_;
46.1819 + Expression *expression_;
46.1820 +
46.1821 + public:
46.1822 + Assignment(const SourcePosition &pos, TokenKind token, Expression *left, Expression *right)
46.1823 + : Expression(pos),
46.1824 + token_(token),
46.1825 + lvalue_(left),
46.1826 + expression_(right)
46.1827 + {
46.1828 + }
46.1829 +
46.1830 + DECLARE_NODE(Assignment);
46.1831 +
46.1832 + TokenKind token() const {
46.1833 + return token_;
46.1834 + }
46.1835 + Expression *lvalue() const {
46.1836 + return lvalue_;
46.1837 + }
46.1838 + Expression *expression() const {
46.1839 + return expression_;
46.1840 + }
46.1841 +};
46.1842 +
46.1843 +class ExpressionStatement : public Statement
46.1844 +{
46.1845 + Expression *expression_;
46.1846 +
46.1847 + public:
46.1848 + ExpressionStatement(Expression *expression)
46.1849 + : Statement(expression->pos()),
46.1850 + expression_(expression)
46.1851 + {
46.1852 + }
46.1853 +
46.1854 + DECLARE_NODE(ExpressionStatement);
46.1855 +
46.1856 + Expression *expression() const {
46.1857 + return expression_;
46.1858 + }
46.1859 +};
46.1860 +
46.1861 +class BlockStatement : public Statement
46.1862 +{
46.1863 + StatementList *statements_;
46.1864 + Scope *scope_;
46.1865 + TokenKind type_;
46.1866 +
46.1867 + public:
46.1868 + BlockStatement(const SourcePosition &pos, StatementList *statements, TokenKind kind)
46.1869 + : Statement(pos),
46.1870 + statements_(statements),
46.1871 + scope_(NULL),
46.1872 + type_(kind)
46.1873 + {
46.1874 + }
46.1875 +
46.1876 + DECLARE_NODE(BlockStatement);
46.1877 +
46.1878 + StatementList *statements() const {
46.1879 + return statements_;
46.1880 + }
46.1881 + Scope *scope() const {
46.1882 + return scope_;
46.1883 + }
46.1884 + void setScope(Scope *scope) {
46.1885 + scope_ = scope;
46.1886 + }
46.1887 + TokenKind type() const {
46.1888 + return type_;
46.1889 + }
46.1890 +};
46.1891 +
46.1892 +typedef PoolList<Parameter *> ParameterList;
46.1893 +
46.1894 +class FunctionSignature
46.1895 +{
46.1896 + public:
46.1897 + FunctionSignature(Expression *returnType, ParameterList *parameters, bool variadic)
46.1898 + : returnType_(returnType),
46.1899 + parameters_(parameters),
46.1900 + variadic_(variadic)
46.1901 + {
46.1902 + }
46.1903 +
46.1904 + Expression *returnType() const {
46.1905 + return returnType_;
46.1906 + }
46.1907 + ParameterList *parameters() const {
46.1908 + return parameters_;
46.1909 + }
46.1910 + bool variadic() const {
46.1911 + return variadic_;
46.1912 + }
46.1913 +
46.1914 + private:
46.1915 + Expression *returnType_;
46.1916 + ParameterList *parameters_;
46.1917 + bool variadic_;
46.1918 +};
46.1919 +
46.1920 +class FunctionTypeStatement : public Statement
46.1921 +{
46.1922 + public:
46.1923 + FunctionTypeStatement(const SourcePosition &pos, Handle<String> name, const FunctionSignature &signature)
46.1924 + : Statement(pos),
46.1925 + name_(name),
46.1926 + signature_(signature)
46.1927 + {
46.1928 + }
46.1929 +
46.1930 + DECLARE_NODE(FunctionTypeStatement);
46.1931 +
46.1932 + Handle<String> name() const {
46.1933 + return name_;
46.1934 + }
46.1935 + const FunctionSignature &signature() const {
46.1936 + return signature_;
46.1937 + }
46.1938 +
46.1939 + private:
46.1940 + ScopedRoot<String> name_;
46.1941 + FunctionSignature signature_;
46.1942 +
46.1943 +};
46.1944 +
46.1945 +class FunctionStatement : public Statement
46.1946 +{
46.1947 + ScopedRoot<String> name_;
46.1948 + TokenKind kind_;
46.1949 + Statement *body_;
46.1950 + FunctionSignature signature_;
46.1951 + bool explicitReturn_;
46.1952 + FunctionSymbol *sym_;
46.1953 + Scope *argScope_;
46.1954 + Scope *varScope_;
46.1955 +
46.1956 + public:
46.1957 + FunctionStatement(const SourcePosition &pos, Handle<String> name, TokenKind kind,
46.1958 + Statement *body, const FunctionSignature &signature, bool explicitReturn)
46.1959 + : Statement(pos),
46.1960 + name_(name),
46.1961 + kind_(kind),
46.1962 + body_(body),
46.1963 + signature_(signature),
46.1964 + explicitReturn_(explicitReturn),
46.1965 + sym_(NULL),
46.1966 + argScope_(NULL),
46.1967 + varScope_(NULL)
46.1968 + {
46.1969 + }
46.1970 +
46.1971 + DECLARE_NODE(FunctionStatement);
46.1972 +
46.1973 + Handle<String> name() const {
46.1974 + return name_;
46.1975 + }
46.1976 + Statement *body() const {
46.1977 + return body_;
46.1978 + }
46.1979 + const FunctionSignature &signature() {
46.1980 + return signature_;
46.1981 + }
46.1982 + bool hasExplicitReturn() const {
46.1983 + return explicitReturn_;
46.1984 + }
46.1985 + TokenKind token() const {
46.1986 + return kind_;
46.1987 + }
46.1988 + void setSymbol(FunctionSymbol *sym) {
46.1989 + assert(!sym_);
46.1990 + sym_ = sym;
46.1991 + }
46.1992 + FunctionSymbol *sym() const {
46.1993 + return sym_;
46.1994 + }
46.1995 + void setScopes(Scope *argScope, Scope *varScope) {
46.1996 + argScope_ = argScope;
46.1997 + varScope_ = varScope;
46.1998 + }
46.1999 + Scope *argScope() const {
46.2000 + return argScope_;
46.2001 + }
46.2002 + Scope *varScope() const {
46.2003 + return varScope_;
46.2004 + }
46.2005 +};
46.2006 +
46.2007 +class IfStatement : public Statement
46.2008 +{
46.2009 + Expression *condition_;
46.2010 + Statement *ifTrue_;
46.2011 + Statement *ifFalse_;
46.2012 +
46.2013 + public:
46.2014 + IfStatement(const SourcePosition &pos, Expression *condition, Statement *ifTrue)
46.2015 + : Statement(pos),
46.2016 + condition_(condition),
46.2017 + ifTrue_(ifTrue),
46.2018 + ifFalse_(NULL)
46.2019 + {
46.2020 + }
46.2021 +
46.2022 + DECLARE_NODE(IfStatement);
46.2023 +
46.2024 + Expression *condition() const {
46.2025 + return condition_;
46.2026 + }
46.2027 + Statement *ifTrue() const {
46.2028 + return ifTrue_;
46.2029 + }
46.2030 + Statement *ifFalse() const {
46.2031 + return ifFalse_;
46.2032 + }
46.2033 + void setIfFalse(Statement *ifFalse) {
46.2034 + ifFalse_ = ifFalse;
46.2035 + }
46.2036 +};
46.2037 +
46.2038 +class EnumStatement : public Statement
46.2039 +{
46.2040 + ScopedRoot<String> name_;
46.2041 + TypeSymbol *sym_;
46.2042 +
46.2043 + public:
46.2044 + struct Entry {
46.2045 + ScopedRoot<String> name;
46.2046 + Expression *expr;
46.2047 + SourcePosition pos;
46.2048 + ConstantSymbol *sym;
46.2049 +
46.2050 + Entry(Handle<String> name, Expression *expr, const SourcePosition &pos)
46.2051 + : name(name),
46.2052 + expr(expr),
46.2053 + pos(pos),
46.2054 + sym(NULL)
46.2055 + {
46.2056 + }
46.2057 + };
46.2058 +
46.2059 + typedef PoolList<Entry> EntryList;
46.2060 +
46.2061 + public:
46.2062 + EnumStatement(const SourcePosition &pos, TokenKind visibility, Handle<String> name, EntryList *entries)
46.2063 + : Statement(pos),
46.2064 + name_(name),
46.2065 + sym_(NULL),
46.2066 + entries_(entries),
46.2067 + visibility_(visibility)
46.2068 + {
46.2069 + }
46.2070 +
46.2071 + DECLARE_NODE(EnumStatement);
46.2072 +
46.2073 + Handle<String> name() const {
46.2074 + return name_;
46.2075 + }
46.2076 + EntryList *entries() const {
46.2077 + return entries_;
46.2078 + }
46.2079 + void setSymbol(TypeSymbol *sym) {
46.2080 + assert(!sym_);
46.2081 + sym_ = sym;
46.2082 + }
46.2083 + TypeSymbol *sym() const {
46.2084 + return sym_;
46.2085 + }
46.2086 + TokenKind visibility() const {
46.2087 + return visibility_;
46.2088 + }
46.2089 +
46.2090 + private:
46.2091 + EntryList *entries_;
46.2092 + TokenKind visibility_;
46.2093 +};
46.2094 +
46.2095 +class IncDecExpression : public Expression
46.2096 +{
46.2097 + TokenKind token_;
46.2098 + Expression *expression_;
46.2099 + bool postfix_;
46.2100 +
46.2101 + public:
46.2102 + IncDecExpression(const SourcePosition &pos, TokenKind token, Expression *expression, bool postfix)
46.2103 + : Expression(pos),
46.2104 + token_(token),
46.2105 + expression_(expression),
46.2106 + postfix_(postfix)
46.2107 + {
46.2108 + }
46.2109 +
46.2110 + DECLARE_NODE(IncDecExpression);
46.2111 +
46.2112 + TokenKind token() const {
46.2113 + return token_;
46.2114 + }
46.2115 + Expression *expression() const {
46.2116 + return expression_;
46.2117 + }
46.2118 + bool postfix() const {
46.2119 + return postfix_;
46.2120 + }
46.2121 +};
46.2122 +
46.2123 +class Case : public PoolObject
46.2124 +{
46.2125 + public:
46.2126 + Case(Expression *expression, ExpressionList *others, Statement *statement)
46.2127 + : expression_(expression),
46.2128 + others_(others),
46.2129 + statement_(statement)
46.2130 + {
46.2131 + }
46.2132 +
46.2133 + Expression *expression() const {
46.2134 + return expression_;
46.2135 + }
46.2136 + PoolList<Expression *> *others() const {
46.2137 + return others_;
46.2138 + }
46.2139 + Statement *statement() const {
46.2140 + return statement_;
46.2141 + }
46.2142 +
46.2143 + private:
46.2144 + Expression *expression_;
46.2145 + PoolList <Expression *> *others_;
46.2146 + Statement *statement_;
46.2147 +};
46.2148 +
46.2149 +struct CaseValue
46.2150 +{
46.2151 + BoxedPrimitive box;
46.2152 + size_t statement;
46.2153 +
46.2154 + CaseValue(size_t statement)
46.2155 + : statement(statement)
46.2156 + {
46.2157 + }
46.2158 +};
46.2159 +
46.2160 +typedef PoolList<CaseValue> CaseValueList;
46.2161 +
46.2162 +class SwitchStatement : public Statement
46.2163 +{
46.2164 + public:
46.2165 + SwitchStatement(const SourcePosition &pos, Expression *expression, PoolList<Case *> *cases,
46.2166 + Statement *def)
46.2167 + : Statement(pos),
46.2168 + expression_(expression),
46.2169 + cases_(cases),
46.2170 + default_(def),
46.2171 + table_(NULL)
46.2172 + {
46.2173 + }
46.2174 +
46.2175 + DECLARE_NODE(SwitchStatement);
46.2176 +
46.2177 + Expression *expression() const {
46.2178 + return expression_;
46.2179 + }
46.2180 + PoolList<Case *> *cases() const {
46.2181 + return cases_;
46.2182 + }
46.2183 + Statement *defaultCase() const {
46.2184 + return default_;
46.2185 + }
46.2186 + void setCaseValueList(CaseValueList *list) {
46.2187 + table_ = list;
46.2188 + }
46.2189 + CaseValueList *caseValueList() const {
46.2190 + return table_;
46.2191 + }
46.2192 +
46.2193 + private:
46.2194 + Expression *expression_;
46.2195 + PoolList<Case *> *cases_;
46.2196 + Statement *default_;
46.2197 + CaseValueList *table_;
46.2198 +};
46.2199 +
46.2200 +class StructureStatement : public Statement
46.2201 +{
46.2202 + public:
46.2203 + class Field : public PoolObject
46.2204 + {
46.2205 + SourcePosition pos_;
46.2206 + Expression *type_;
46.2207 + ScopedRoot<String> name_;
46.2208 +
46.2209 + public:
46.2210 + Field(const SourcePosition &pos,
46.2211 + Expression *type,
46.2212 + Handle<String> name)
46.2213 + : pos_(pos),
46.2214 + type_(type),
46.2215 + name_(name)
46.2216 + {
46.2217 + }
46.2218 +
46.2219 + const SourcePosition &pos() const {
46.2220 + return pos_;
46.2221 + }
46.2222 + Handle<String> name() const {
46.2223 + return name_;
46.2224 + }
46.2225 + Expression *type() const {
46.2226 + return type_;
46.2227 + }
46.2228 + };
46.2229 +
46.2230 + typedef PoolList<StructureStatement::Field *> FieldList;
46.2231 +
46.2232 + public:
46.2233 + StructureStatement(const SourcePosition &pos, Handle<String> name, FieldList *fields)
46.2234 + : Statement(pos),
46.2235 + name_(name),
46.2236 + fields_(fields),
46.2237 + sym_(NULL)
46.2238 + {
46.2239 + }
46.2240 +
46.2241 + DECLARE_NODE(StructureStatement);
46.2242 +
46.2243 + FieldList *fields() const {
46.2244 + return fields_;
46.2245 + }
46.2246 + Handle<String> name() const {
46.2247 + return name_;
46.2248 + }
46.2249 + void setSymbol(TypeSymbol *sym) {
46.2250 + assert(!sym_);
46.2251 + sym_ = sym;
46.2252 + }
46.2253 + TypeSymbol *sym() const {
46.2254 + return sym_;
46.2255 + }
46.2256 +
46.2257 + private:
46.2258 + ScopedRoot<String> name_;
46.2259 + FieldList *fields_;
46.2260 + TypeSymbol *sym_;
46.2261 +};
46.2262 +
46.2263 +typedef PoolList<ScopedRoot<String> *> NameList;
46.2264 +
46.2265 +class ImportStatement : public Statement
46.2266 +{
46.2267 + public:
46.2268 + ImportStatement(const SourcePosition &pos, PathComponent *path, NameList *names)
46.2269 + : Statement(pos),
46.2270 + path_(path),
46.2271 + names_(names)
46.2272 + {
46.2273 + }
46.2274 +
46.2275 + DECLARE_NODE(ImportStatement);
46.2276 +
46.2277 + PathComponent *path() const {
46.2278 + return path_;
46.2279 + }
46.2280 + void setSource(Importable *source) {
46.2281 + source_ = source;
46.2282 + }
46.2283 + Handle<Importable> source() {
46.2284 + return source_;
46.2285 + }
46.2286 + unsigned importIndex() const {
46.2287 + return importIndex_;
46.2288 + }
46.2289 + void setImportIndex(unsigned index) {
46.2290 + importIndex_ = index;
46.2291 + }
46.2292 + NameList *names() const {
46.2293 + return names_;
46.2294 + }
46.2295 +
46.2296 + bool importAllNames() const {
46.2297 + return names_ && names_->empty();
46.2298 + }
46.2299 +
46.2300 + private:
46.2301 + PathComponent *path_;
46.2302 + ScopedRoot<Importable> source_;
46.2303 + unsigned importIndex_;
46.2304 + NameList *names_;
46.2305 +};
46.2306 +
46.2307 +typedef StructureStatement::FieldList FieldList;
46.2308 +typedef PoolList<NameProxy *> NameProxyList;
46.2309 +
46.2310 +#undef DECLARE_NODE
46.2311 +
46.2312 +class ParseTree : public PoolObject
46.2313 +{
46.2314 + StatementList *statements_;
46.2315 + NameProxyList *unbound_;
46.2316 + PoolList<ImportStatement *> *imports_;
46.2317 +
46.2318 + public:
46.2319 + ParseTree(StatementList *statements, NameProxyList *unbound, PoolList<ImportStatement *> *imports)
46.2320 + : statements_(statements),
46.2321 + unbound_(unbound),
46.2322 + imports_(imports)
46.2323 + {
46.2324 + }
46.2325 +
46.2326 + void dump(FILE *fp);
46.2327 +
46.2328 + StatementList *statements() const {
46.2329 + return statements_;
46.2330 + }
46.2331 + NameProxyList *unbound() const {
46.2332 + return unbound_;
46.2333 + }
46.2334 + PoolList<ImportStatement *> *imports() const {
46.2335 + return imports_;
46.2336 + }
46.2337 +};
46.2338 +
46.2339 +}
46.2340 +
46.2341 +#endif // _include_sourcepawn_ast_h_
47.1 --- a/src/compiler/BytecodeEmitter.cpp Mon Jun 10 00:46:29 2013 +0100
47.2 +++ b/src/compiler/BytecodeEmitter.cpp Mon Jun 10 01:04:43 2013 +0100
47.3 @@ -1,386 +1,386 @@
47.4 -/* vim: set ts=4 sw=4 tw=99 et:
47.5 - *
47.6 - * Copyright (C) 2012 David Anderson
47.7 - *
47.8 - * This file is part of JITCraft.
47.9 - *
47.10 - * JITCraft is free software: you can redistribute it and/or modify it under
47.11 - * the terms of the GNU General Public License as published by the Free
47.12 - * Software Foundation, either version 3 of the License, or (at your option)
47.13 - * any later version.
47.14 - *
47.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
47.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
47.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
47.18 - *
47.19 - * You should have received a copy of the GNU General Public License along with
47.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
47.21 - */
47.22 -#include <stdlib.h>
47.23 -#include <string.h>
47.24 -#include "../Utility.h"
47.25 -#include "../Types.h"
47.26 -#include "../Zone.h"
47.27 -#include "../Strings.h"
47.28 -#include "../Zone.h"
47.29 -#include "BytecodeEmitter.h"
47.30 -#include "Symbols.h"
47.31 -#include "Scopes.h"
47.32 -#include "../Spaces-inl.h"
47.33 -#include "../Heap-inl.h"
47.34 -
47.35 -using namespace ke;
47.36 -
47.37 -StringTable::StringTable()
47.38 - : set_(ZoneAllocatorPolicy()),
47.39 - initialized_(false)
47.40 -{
47.41 -}
47.42 -
47.43 -bool
47.44 -StringTable::initialize()
47.45 -{
47.46 - assert(!initialized_);
47.47 - initialized_ = true;
47.48 - if (!set_.init(16))
47.49 - return false;
47.50 - return true;
47.51 -}
47.52 -
47.53 -bool
47.54 -StringTable::add(Handle<String> name, unsigned *indexp)
47.55 -{
47.56 - if (!initialized_ && !initialize())
47.57 - return false;
47.58 -
47.59 - Set::Insert p = set_.findForAdd(*name);
47.60 - if (p.found()) {
47.61 - *indexp = p->index;
47.62 - return true;
47.63 - }
47.64 -
47.65 - if (strings_.length() > INT_MAX) {
47.66 - ZONE()->reportAllocationOverflow();
47.67 - return false;
47.68 - }
47.69 -
47.70 - Entry e(name, strings_.length());
47.71 - if (!strings_.append(e))
47.72 - return false;
47.73 -
47.74 - if (!set_.add(p, e))
47.75 - return false;
47.76 -
47.77 - *indexp = e.index;
47.78 -
47.79 - return true;
47.80 -}
47.81 -
47.82 -void
47.83 -StringTable::accept(VirtualObjectVisitor *visitor)
47.84 -{
47.85 - for (size_t i = 0; i < strings_.length(); i++)
47.86 - visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
47.87 -}
47.88 -
47.89 -BytecodeEmitter::BytecodeEmitter()
47.90 - : AutoRooted(ZONE()),
47.91 - buffer_(inline_buffer_),
47.92 - buffer_pos_(buffer_),
47.93 - buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
47.94 - oom_(false),
47.95 - maxStackDepth_(0),
47.96 - loopDepth_(0),
47.97 - maxLoopDepth_(0)
47.98 -{
47.99 - lastCodePosition_ = 0;
47.100 - firstLine_ = 1;
47.101 -}
47.102 -
47.103 -BytecodeEmitter::~BytecodeEmitter()
47.104 -{
47.105 - for (size_t i = 0; i < oopRecords_.length(); i++)
47.106 - delete oopRecords_[i];
47.107 -}
47.108 -
47.109 -void
47.110 -BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
47.111 -{
47.112 - for (size_t i = 0; i < objects_.length(); i++)
47.113 - visitor->visit(&objects_[i]);
47.114 -
47.115 - strings_.accept(visitor);
47.116 -}
47.117 -
47.118 -bool
47.119 -BytecodeEmitter::growBuffer(size_t nbytes)
47.120 -{
47.121 - if (oom_) {
47.122 - buffer_pos_ = buffer_;
47.123 - return false;
47.124 - }
47.125 -
47.126 - size_t newSize = size_t((buffer_end_ - buffer_) * 2);
47.127 - if (newSize >= MAX_LENGTH) {
47.128 - oom_ = true;
47.129 - buffer_pos_ = buffer_;
47.130 - ZONE()->reportOutOfMemory();
47.131 - return false;
47.132 - }
47.133 -
47.134 - bytecode *newBuffer;
47.135 - if (buffer_ == inline_buffer_)
47.136 - newBuffer = (bytecode *)malloc(newSize);
47.137 - else
47.138 - newBuffer = (bytecode *)realloc(buffer_, newSize);
47.139 -
47.140 - // If we can't allocate a buffer, reset the buffer to the start and set
47.141 - // a flag to indicate out-of-memory.
47.142 - if (!newBuffer) {
47.143 - oom_ = true;
47.144 - buffer_pos_ = buffer_;
47.145 - ZONE()->reportOutOfMemory();
47.146 - return false;
47.147 - }
47.148 -
47.149 - if (buffer_ == inline_buffer_)
47.150 - memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
47.151 -
47.152 - buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
47.153 - buffer_ = newBuffer;
47.154 - buffer_end_ = buffer_ + newSize;
47.155 - assert(buffer_pos_ + nbytes < buffer_end_);
47.156 -
47.157 - return true;
47.158 -}
47.159 -
47.160 -void
47.161 -BytecodeEmitter::recordOops()
47.162 -{
47.163 - OopRecord *record = new OopRecord(oopMap_.length(), position());
47.164 -
47.165 - if (!record->slots.ensure(record->depth)) {
47.166 - oom_ = true;
47.167 - return;
47.168 - }
47.169 -
47.170 - bool hadOops = false;
47.171 - for (size_t i = 0; i < oopMap_.length(); i++) {
47.172 - bool bit = oopMap_[i];
47.173 - record->slots.infallibleAppend(bit);
47.174 - hadOops |= bit;
47.175 - }
47.176 -
47.177 - if (!hadOops) {
47.178 - delete record;
47.179 - return;
47.180 - }
47.181 -
47.182 - oom_ &= oopRecords_.append(record);
47.183 -}
47.184 -
47.185 -void
47.186 -BytecodeEmitter::note_position(const SourcePosition &pos)
47.187 -{
47.188 - assert(pos.line > 0);
47.189 - assert(unsigned(pos.line) >= firstLine_);
47.190 -
47.191 - unsigned lineDelta = unsigned(pos.line) - firstLine_;
47.192 - unsigned pcDelta = unsigned(position()) - lastCodePosition_;
47.193 -
47.194 - sourcemap_.writeUint32(pcDelta);
47.195 - sourcemap_.writeUint32(lineDelta);
47.196 - sourcemap_.writeUint32(pos.col);
47.197 -
47.198 - lastCodePosition_ = unsigned(position());
47.199 -}
47.200 -
47.201 -void
47.202 -BytecodeEmitter::getglobal(Symbol *sym)
47.203 -{
47.204 - ensure(OP_GETGLOBAL_LENGTH);
47.205 - writeOp(OP_GETGLOBAL);
47.206 - writeUint32(addString(sym->name()));
47.207 - if (sym->type()->isTraceable())
47.208 - markOop(1);
47.209 -}
47.210 -void
47.211 -BytecodeEmitter::setglobal(Symbol *sym)
47.212 -{
47.213 - ensure(OP_SETGLOBAL_LENGTH);
47.214 - writeOp(OP_SETGLOBAL);
47.215 - writeUint32(addString(sym->name()));
47.216 - if (sym->type()->isTraceable())
47.217 - markOop(1);
47.218 -}
47.219 -
47.220 -void
47.221 -BytecodeEmitter::getlocal(VariableSymbol *var)
47.222 -{
47.223 - assert(var->storage() == VariableSymbol::Local);
47.224 - ensure(OP_GETLOCAL_LENGTH);
47.225 - writeOp(OP_GETLOCAL);
47.226 - writeUint32(var->slot());
47.227 - if (var->type()->isTraceable())
47.228 - markOop(1);
47.229 -}
47.230 -
47.231 -void
47.232 -BytecodeEmitter::setlocal(VariableSymbol *var)
47.233 -{
47.234 - assert(var->storage() == VariableSymbol::Local);
47.235 - ensure(OP_SETLOCAL_LENGTH);
47.236 - writeOp(OP_SETLOCAL);
47.237 - writeUint32(var->slot());
47.238 - if (var->type()->isTraceable())
47.239 - markOop(1);
47.240 -}
47.241 -
47.242 -void
47.243 -BytecodeEmitter::getarg(VariableSymbol *var)
47.244 -{
47.245 - assert(var->storage() == VariableSymbol::Arg);
47.246 - ensure(OP_GETARG_LENGTH);
47.247 - writeOp(OP_GETARG);
47.248 - writeUint32(var->slot());
47.249 - if (var->type()->isTraceable())
47.250 - markOop(1);
47.251 -}
47.252 -
47.253 -void
47.254 -BytecodeEmitter::setarg(VariableSymbol *var)
47.255 -{
47.256 - assert(var->storage() == VariableSymbol::Arg);
47.257 - ensure(OP_SETARG_LENGTH);
47.258 - writeOp(OP_SETARG);
47.259 - writeUint32(var->slot());
47.260 - if (var->type()->isTraceable())
47.261 - markOop(1);
47.262 -}
47.263 -
47.264 -bool
47.265 -BytecodeEmitter::allocate(VariableSymbol *sym)
47.266 -{
47.267 - assert(sym->isVariable());
47.268 - assert(sym->scope()->kind() == Scope::BLOCK);
47.269 -
47.270 - switch (sym->scope()->kind()) {
47.271 - case Scope::BLOCK:
47.272 - {
47.273 - // See overall comment on overflows.
47.274 - assert(locals_.length() < UINT_MAX);
47.275 - sym->allocate(VariableSymbol::Local, locals_.length());
47.276 - if (!locals_.append(sym))
47.277 - return false;
47.278 - break;
47.279 - }
47.280 -
47.281 - default:
47.282 - assert(false);
47.283 - return false;
47.284 - }
47.285 -
47.286 - return true;
47.287 -}
47.288 -
47.289 -void
47.290 -BytecodeEmitter::newref(VariableSymbol *var)
47.291 -{
47.292 - recordOops();
47.293 - if (var->storage() == VariableSymbol::Local) {
47.294 - ensure(OP_VARREF_LIFO_LENGTH);
47.295 - writeOp(OP_VARREF_LIFO);
47.296 - } else {
47.297 - assert(var->storage() == VariableSymbol::Arg);
47.298 - ensure(OP_ARGREF_LIFO_LENGTH);
47.299 - writeOp(OP_ARGREF_LIFO);
47.300 - }
47.301 - writeUint32(var->slot());
47.302 - markOop(1);
47.303 -}
47.304 -
47.305 -Code *
47.306 -BytecodeEmitter::finish()
47.307 -{
47.308 - stop();
47.309 -
47.310 - Zone *zone = ZONE();
47.311 - if (oom() || zone->hasPendingException())
47.312 - return NULL;
47.313 -
47.314 - Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
47.315 - if (!bytes)
47.316 - return NULL;
47.317 - memcpy(bytes->raw(), buffer(), length());
47.318 -
47.319 - Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
47.320 - if (!objects)
47.321 - return NULL;
47.322 -
47.323 - for (size_t i = 0; i < objects_.length(); i++)
47.324 - objects->set(zone, i, objects_[i]);
47.325 -
47.326 - // If any stack slots hold gc pointers at potential failure points in the
47.327 - // bytecode, record them now. We do this by building a list of tuples;
47.328 - // each tuple contains the pc offset, and a bitset containing which stack
47.329 - // slots must be scanned by the gc.
47.330 - Local<ByteArray> safepoints(zone);
47.331 - if (oopRecords_.length()) {
47.332 - size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
47.333 - size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
47.334 - safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
47.335 - if (!safepoints)
47.336 - return NULL;
47.337 -
47.338 - Address cursor = safepoints->raw();
47.339 - for (size_t i = 0; i < oopRecords_.length(); i++) {
47.340 - OopRecord *record = oopRecords_[i];
47.341 - assert(record->depth <= maxStackDepth());
47.342 -
47.343 - *reinterpret_cast<unsigned *>(cursor) = record->offset;
47.344 -
47.345 - unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
47.346 - for (unsigned i = 0; i < record->depth; i++)
47.347 - bits[i / 8] |= (1 << (i % 8));
47.348 -
47.349 - cursor += bytesPerSafepoint;
47.350 - }
47.351 -
47.352 - assert(cursor == safepoints->raw() + gcmapSize);
47.353 - }
47.354 -
47.355 - Local<ByteArray> sourcemap(zone);
47.356 - if (sourcemap_.length()) {
47.357 - sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
47.358 - if (!sourcemap)
47.359 - return NULL;
47.360 -
47.361 - memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
47.362 - }
47.363 -
47.364 - Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
47.365 - if (!strings)
47.366 - return NULL;
47.367 - for (size_t i = 0; i < strings_.stringCount(); i++)
47.368 - strings->set(zone, i, strings_.stringAt(i));
47.369 -
47.370 - Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
47.371 - if (!locals)
47.372 - return NULL;
47.373 - for (size_t i = 0; i < locals_.length(); i++)
47.374 - locals->set(zone, i, locals_[i]->type());
47.375 -
47.376 - Local<Code> code(zone);
47.377 -
47.378 - code = Code::New(zone,
47.379 - bytes,
47.380 - locals,
47.381 - objects,
47.382 - strings,
47.383 - maxStackDepth(),
47.384 - maxLoopDepth_,
47.385 - safepoints,
47.386 - sourcemap);
47.387 -
47.388 - return code;
47.389 -}
47.390 +/* vim: set ts=4 sw=4 tw=99 et:
47.391 + *
47.392 + * Copyright (C) 2012 David Anderson
47.393 + *
47.394 + * This file is part of JITCraft.
47.395 + *
47.396 + * JITCraft is free software: you can redistribute it and/or modify it under
47.397 + * the terms of the GNU General Public License as published by the Free
47.398 + * Software Foundation, either version 3 of the License, or (at your option)
47.399 + * any later version.
47.400 + *
47.401 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
47.402 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
47.403 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
47.404 + *
47.405 + * You should have received a copy of the GNU General Public License along with
47.406 + * JITCraft. If not, see http://www.gnu.org/licenses/.
47.407 + */
47.408 +#include <stdlib.h>
47.409 +#include <string.h>
47.410 +#include "../Utility.h"
47.411 +#include "../Types.h"
47.412 +#include "../Zone.h"
47.413 +#include "../Strings.h"
47.414 +#include "../Zone.h"
47.415 +#include "BytecodeEmitter.h"
47.416 +#include "Symbols.h"
47.417 +#include "Scopes.h"
47.418 +#include "../Spaces-inl.h"
47.419 +#include "../Heap-inl.h"
47.420 +
47.421 +using namespace ke;
47.422 +
47.423 +StringTable::StringTable()
47.424 + : set_(ZoneAllocatorPolicy()),
47.425 + initialized_(false)
47.426 +{
47.427 +}
47.428 +
47.429 +bool
47.430 +StringTable::initialize()
47.431 +{
47.432 + assert(!initialized_);
47.433 + initialized_ = true;
47.434 + if (!set_.init(16))
47.435 + return false;
47.436 + return true;
47.437 +}
47.438 +
47.439 +bool
47.440 +StringTable::add(Handle<String> name, unsigned *indexp)
47.441 +{
47.442 + if (!initialized_ && !initialize())
47.443 + return false;
47.444 +
47.445 + Set::Insert p = set_.findForAdd(*name);
47.446 + if (p.found()) {
47.447 + *indexp = p->index;
47.448 + return true;
47.449 + }
47.450 +
47.451 + if (strings_.length() > INT_MAX) {
47.452 + ZONE()->reportAllocationOverflow();
47.453 + return false;
47.454 + }
47.455 +
47.456 + Entry e(name, strings_.length());
47.457 + if (!strings_.append(e))
47.458 + return false;
47.459 +
47.460 + if (!set_.add(p, e))
47.461 + return false;
47.462 +
47.463 + *indexp = e.index;
47.464 +
47.465 + return true;
47.466 +}
47.467 +
47.468 +void
47.469 +StringTable::accept(VirtualObjectVisitor *visitor)
47.470 +{
47.471 + for (size_t i = 0; i < strings_.length(); i++)
47.472 + visitor->visit(reinterpret_cast<Object **>(&strings_[i].string));
47.473 +}
47.474 +
47.475 +BytecodeEmitter::BytecodeEmitter()
47.476 + : AutoRooted(ZONE()),
47.477 + buffer_(inline_buffer_),
47.478 + buffer_pos_(buffer_),
47.479 + buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
47.480 + oom_(false),
47.481 + maxStackDepth_(0),
47.482 + loopDepth_(0),
47.483 + maxLoopDepth_(0)
47.484 +{
47.485 + lastCodePosition_ = 0;
47.486 + firstLine_ = 1;
47.487 +}
47.488 +
47.489 +BytecodeEmitter::~BytecodeEmitter()
47.490 +{
47.491 + for (size_t i = 0; i < oopRecords_.length(); i++)
47.492 + delete oopRecords_[i];
47.493 +}
47.494 +
47.495 +void
47.496 +BytecodeEmitter::accept(VirtualObjectVisitor *visitor)
47.497 +{
47.498 + for (size_t i = 0; i < objects_.length(); i++)
47.499 + visitor->visit(&objects_[i]);
47.500 +
47.501 + strings_.accept(visitor);
47.502 +}
47.503 +
47.504 +bool
47.505 +BytecodeEmitter::growBuffer(size_t nbytes)
47.506 +{
47.507 + if (oom_) {
47.508 + buffer_pos_ = buffer_;
47.509 + return false;
47.510 + }
47.511 +
47.512 + size_t newSize = size_t((buffer_end_ - buffer_) * 2);
47.513 + if (newSize >= MAX_LENGTH) {
47.514 + oom_ = true;
47.515 + buffer_pos_ = buffer_;
47.516 + ZONE()->reportOutOfMemory();
47.517 + return false;
47.518 + }
47.519 +
47.520 + bytecode *newBuffer;
47.521 + if (buffer_ == inline_buffer_)
47.522 + newBuffer = (bytecode *)malloc(newSize);
47.523 + else
47.524 + newBuffer = (bytecode *)realloc(buffer_, newSize);
47.525 +
47.526 + // If we can't allocate a buffer, reset the buffer to the start and set
47.527 + // a flag to indicate out-of-memory.
47.528 + if (!newBuffer) {
47.529 + oom_ = true;
47.530 + buffer_pos_ = buffer_;
47.531 + ZONE()->reportOutOfMemory();
47.532 + return false;
47.533 + }
47.534 +
47.535 + if (buffer_ == inline_buffer_)
47.536 + memcpy(newBuffer, inline_buffer_, (buffer_pos_ - inline_buffer_));
47.537 +
47.538 + buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
47.539 + buffer_ = newBuffer;
47.540 + buffer_end_ = buffer_ + newSize;
47.541 + assert(buffer_pos_ + nbytes < buffer_end_);
47.542 +
47.543 + return true;
47.544 +}
47.545 +
47.546 +void
47.547 +BytecodeEmitter::recordOops()
47.548 +{
47.549 + OopRecord *record = new OopRecord(oopMap_.length(), position());
47.550 +
47.551 + if (!record->slots.ensure(record->depth)) {
47.552 + oom_ = true;
47.553 + return;
47.554 + }
47.555 +
47.556 + bool hadOops = false;
47.557 + for (size_t i = 0; i < oopMap_.length(); i++) {
47.558 + bool bit = oopMap_[i];
47.559 + record->slots.infallibleAppend(bit);
47.560 + hadOops |= bit;
47.561 + }
47.562 +
47.563 + if (!hadOops) {
47.564 + delete record;
47.565 + return;
47.566 + }
47.567 +
47.568 + oom_ &= oopRecords_.append(record);
47.569 +}
47.570 +
47.571 +void
47.572 +BytecodeEmitter::note_position(const SourcePosition &pos)
47.573 +{
47.574 + assert(pos.line > 0);
47.575 + assert(unsigned(pos.line) >= firstLine_);
47.576 +
47.577 + unsigned lineDelta = unsigned(pos.line) - firstLine_;
47.578 + unsigned pcDelta = unsigned(position()) - lastCodePosition_;
47.579 +
47.580 + sourcemap_.writeUint32(pcDelta);
47.581 + sourcemap_.writeUint32(lineDelta);
47.582 + sourcemap_.writeUint32(pos.col);
47.583 +
47.584 + lastCodePosition_ = unsigned(position());
47.585 +}
47.586 +
47.587 +void
47.588 +BytecodeEmitter::getglobal(Symbol *sym)
47.589 +{
47.590 + ensure(OP_GETGLOBAL_LENGTH);
47.591 + writeOp(OP_GETGLOBAL);
47.592 + writeUint32(addString(sym->name()));
47.593 + if (sym->type()->isTraceable())
47.594 + markOop(1);
47.595 +}
47.596 +void
47.597 +BytecodeEmitter::setglobal(Symbol *sym)
47.598 +{
47.599 + ensure(OP_SETGLOBAL_LENGTH);
47.600 + writeOp(OP_SETGLOBAL);
47.601 + writeUint32(addString(sym->name()));
47.602 + if (sym->type()->isTraceable())
47.603 + markOop(1);
47.604 +}
47.605 +
47.606 +void
47.607 +BytecodeEmitter::getlocal(VariableSymbol *var)
47.608 +{
47.609 + assert(var->storage() == VariableSymbol::Local);
47.610 + ensure(OP_GETLOCAL_LENGTH);
47.611 + writeOp(OP_GETLOCAL);
47.612 + writeUint32(var->slot());
47.613 + if (var->type()->isTraceable())
47.614 + markOop(1);
47.615 +}
47.616 +
47.617 +void
47.618 +BytecodeEmitter::setlocal(VariableSymbol *var)
47.619 +{
47.620 + assert(var->storage() == VariableSymbol::Local);
47.621 + ensure(OP_SETLOCAL_LENGTH);
47.622 + writeOp(OP_SETLOCAL);
47.623 + writeUint32(var->slot());
47.624 + if (var->type()->isTraceable())
47.625 + markOop(1);
47.626 +}
47.627 +
47.628 +void
47.629 +BytecodeEmitter::getarg(VariableSymbol *var)
47.630 +{
47.631 + assert(var->storage() == VariableSymbol::Arg);
47.632 + ensure(OP_GETARG_LENGTH);
47.633 + writeOp(OP_GETARG);
47.634 + writeUint32(var->slot());
47.635 + if (var->type()->isTraceable())
47.636 + markOop(1);
47.637 +}
47.638 +
47.639 +void
47.640 +BytecodeEmitter::setarg(VariableSymbol *var)
47.641 +{
47.642 + assert(var->storage() == VariableSymbol::Arg);
47.643 + ensure(OP_SETARG_LENGTH);
47.644 + writeOp(OP_SETARG);
47.645 + writeUint32(var->slot());
47.646 + if (var->type()->isTraceable())
47.647 + markOop(1);
47.648 +}
47.649 +
47.650 +bool
47.651 +BytecodeEmitter::allocate(VariableSymbol *sym)
47.652 +{
47.653 + assert(sym->isVariable());
47.654 + assert(sym->scope()->kind() == Scope::BLOCK);
47.655 +
47.656 + switch (sym->scope()->kind()) {
47.657 + case Scope::BLOCK:
47.658 + {
47.659 + // See overall comment on overflows.
47.660 + assert(locals_.length() < UINT_MAX);
47.661 + sym->allocate(VariableSymbol::Local, locals_.length());
47.662 + if (!locals_.append(sym))
47.663 + return false;
47.664 + break;
47.665 + }
47.666 +
47.667 + default:
47.668 + assert(false);
47.669 + return false;
47.670 + }
47.671 +
47.672 + return true;
47.673 +}
47.674 +
47.675 +void
47.676 +BytecodeEmitter::newref(VariableSymbol *var)
47.677 +{
47.678 + recordOops();
47.679 + if (var->storage() == VariableSymbol::Local) {
47.680 + ensure(OP_VARREF_LIFO_LENGTH);
47.681 + writeOp(OP_VARREF_LIFO);
47.682 + } else {
47.683 + assert(var->storage() == VariableSymbol::Arg);
47.684 + ensure(OP_ARGREF_LIFO_LENGTH);
47.685 + writeOp(OP_ARGREF_LIFO);
47.686 + }
47.687 + writeUint32(var->slot());
47.688 + markOop(1);
47.689 +}
47.690 +
47.691 +Code *
47.692 +BytecodeEmitter::finish()
47.693 +{
47.694 + stop();
47.695 +
47.696 + Zone *zone = ZONE();
47.697 + if (oom() || zone->hasPendingException())
47.698 + return NULL;
47.699 +
47.700 + Local<ByteArray> bytes(zone, ByteArray::New(zone, length(), Heap::Tenure_Old));
47.701 + if (!bytes)
47.702 + return NULL;
47.703 + memcpy(bytes->raw(), buffer(), length());
47.704 +
47.705 + Local<FixedArray> objects(zone, FixedArray::New(zone, objects_.length(), Heap::Tenure_Old));
47.706 + if (!objects)
47.707 + return NULL;
47.708 +
47.709 + for (size_t i = 0; i < objects_.length(); i++)
47.710 + objects->set(zone, i, objects_[i]);
47.711 +
47.712 + // If any stack slots hold gc pointers at potential failure points in the
47.713 + // bytecode, record them now. We do this by building a list of tuples;
47.714 + // each tuple contains the pc offset, and a bitset containing which stack
47.715 + // slots must be scanned by the gc.
47.716 + Local<ByteArray> safepoints(zone);
47.717 + if (oopRecords_.length()) {
47.718 + size_t bytesPerSafepoint = Code::BytesPerSafepoint(maxStackDepth());
47.719 + size_t gcmapSize = bytesPerSafepoint * oopRecords_.length();
47.720 + safepoints = ByteArray::New(zone, gcmapSize, Heap::Tenure_Old);
47.721 + if (!safepoints)
47.722 + return NULL;
47.723 +
47.724 + Address cursor = safepoints->raw();
47.725 + for (size_t i = 0; i < oopRecords_.length(); i++) {
47.726 + OopRecord *record = oopRecords_[i];
47.727 + assert(record->depth <= maxStackDepth());
47.728 +
47.729 + *reinterpret_cast<unsigned *>(cursor) = record->offset;
47.730 +
47.731 + unsigned char *bits = reinterpret_cast<unsigned char *>(cursor + sizeof(unsigned));
47.732 + for (unsigned i = 0; i < record->depth; i++)
47.733 + bits[i / 8] |= (1 << (i % 8));
47.734 +
47.735 + cursor += bytesPerSafepoint;
47.736 + }
47.737 +
47.738 + assert(cursor == safepoints->raw() + gcmapSize);
47.739 + }
47.740 +
47.741 + Local<ByteArray> sourcemap(zone);
47.742 + if (sourcemap_.length()) {
47.743 + sourcemap = ByteArray::New(zone, sourcemap_.length(), Heap::Tenure_Old);
47.744 + if (!sourcemap)
47.745 + return NULL;
47.746 +
47.747 + memcpy(sourcemap->raw(), sourcemap_.buffer(), sourcemap_.length());
47.748 + }
47.749 +
47.750 + Local<FixedArray> strings(zone, FixedArray::New(zone, strings_.stringCount(), Heap::Tenure_Old));
47.751 + if (!strings)
47.752 + return NULL;
47.753 + for (size_t i = 0; i < strings_.stringCount(); i++)
47.754 + strings->set(zone, i, strings_.stringAt(i));
47.755 +
47.756 + Local<FixedArray> locals(zone, FixedArray::New(zone, locals_.length(), Heap::Tenure_Old));
47.757 + if (!locals)
47.758 + return NULL;
47.759 + for (size_t i = 0; i < locals_.length(); i++)
47.760 + locals->set(zone, i, locals_[i]->type());
47.761 +
47.762 + Local<Code> code(zone);
47.763 +
47.764 + code = Code::New(zone,
47.765 + bytes,
47.766 + locals,
47.767 + objects,
47.768 + strings,
47.769 + maxStackDepth(),
47.770 + maxLoopDepth_,
47.771 + safepoints,
47.772 + sourcemap);
47.773 +
47.774 + return code;
47.775 +}
48.1 --- a/src/compiler/BytecodeEmitter.h Mon Jun 10 00:46:29 2013 +0100
48.2 +++ b/src/compiler/BytecodeEmitter.h Mon Jun 10 01:04:43 2013 +0100
48.3 @@ -1,717 +1,717 @@
48.4 -/* vim: set ts=4 sw=4 tw=99 et:
48.5 - *
48.6 - * Copyright (C) 2012 David Anderson
48.7 - *
48.8 - * This file is part of JITCraft.
48.9 - *
48.10 - * JITCraft is free software: you can redistribute it and/or modify it under
48.11 - * the terms of the GNU General Public License as published by the Free
48.12 - * Software Foundation, either version 3 of the License, or (at your option)
48.13 - * any later version.
48.14 - *
48.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
48.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
48.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
48.18 - *
48.19 - * You should have received a copy of the GNU General Public License along with
48.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
48.21 - */
48.22 -#ifndef _include_bytecode_emitter_h_
48.23 -#define _include_bytecode_emitter_h_
48.24 -
48.25 -#include <assert.h>
48.26 -#include <limits.h>
48.27 -#include "../Opcodes.h"
48.28 -#include "../Handles.h"
48.29 -#include "../CompactBuffer.h"
48.30 -#include "../Array.h"
48.31 -#include "../HashTable.h"
48.32 -#include "../VirtualObjectVisitor.h"
48.33 -
48.34 -namespace ke {
48.35 -
48.36 -// An overarching note on overflows: Though we should use CheckedInt, we rely
48.37 -// on a source-length cap covering all possible overflow checks. As long as
48.38 -// the source length is capped to INT_MAX, the number of AST nodes will be
48.39 -// strictly beneath that cap, and so to will most things generated by the
48.40 -// AST. For example, local and argument counts, number of functions, fields
48.41 -// in a struct, et cetera. Not everything can be covered by this cap: the
48.42 -// stack depth, number of bytecodes for example. In these cases we explicitly
48.43 -// test for overflow of INT_MAX and in other cases we assert.
48.44 -//
48.45 -// In the future, we should of course use a checked int wrapper.
48.46 -
48.47 -class Type;
48.48 -class Map;
48.49 -class ArrayMap;
48.50 -class Symbol;
48.51 -class VariableSymbol;
48.52 -
48.53 -struct OopRecord
48.54 -{
48.55 - unsigned depth;
48.56 - unsigned offset;
48.57 - Vector<bool> slots;
48.58 -
48.59 - OopRecord(unsigned length, unsigned offset)
48.60 - : depth(length),
48.61 - offset(offset)
48.62 - {
48.63 - }
48.64 -};
48.65 -
48.66 -class StringTable
48.67 -{
48.68 - struct Entry
48.69 - {
48.70 - String *string;
48.71 - unsigned index;
48.72 -
48.73 - Entry()
48.74 - : string(NULL),
48.75 - index(0)
48.76 - {
48.77 - }
48.78 -
48.79 - Entry(String *string, unsigned index)
48.80 - : string(string),
48.81 - index(index)
48.82 - {
48.83 - }
48.84 - };
48.85 -
48.86 - struct Policy
48.87 - {
48.88 - typedef Entry Payload;
48.89 -
48.90 - static uint32 hash(String *string) {
48.91 - return HashPointer(string);
48.92 - }
48.93 -
48.94 - static bool matches(String *key, Entry &e) {
48.95 - return key == e.string;
48.96 - }
48.97 - };
48.98 -
48.99 - typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
48.100 -
48.101 - public:
48.102 - StringTable();
48.103 - bool initialize();
48.104 - void accept(VirtualObjectVisitor *visitor);
48.105 -
48.106 - bool add(Handle<String> name, unsigned *indexp);
48.107 - size_t stringCount() const {
48.108 - return strings_.length();
48.109 - }
48.110 - String *stringAt(size_t i) const {
48.111 - return strings_[i].string;
48.112 - }
48.113 -
48.114 - private:
48.115 - Set set_;
48.116 - Vector<Entry> strings_;
48.117 - bool initialized_;
48.118 -};
48.119 -
48.120 -// The bytecode emitter assists in building Code objects, by emitting opcodes
48.121 -// and tracking stack information. Since the SemA creates temporary pool/root
48.122 -// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
48.123 -// special marking function.
48.124 -class BytecodeEmitter : public AutoRooted
48.125 -{
48.126 - private:
48.127 - bytecode *buffer_;
48.128 - bytecode *buffer_pos_;
48.129 - bytecode *buffer_end_;
48.130 - bytecode inline_buffer_[512];
48.131 - bool oom_;
48.132 - unsigned maxStackDepth_;
48.133 - Vector<bool> oopMap_;
48.134 - Vector<OopRecord *> oopRecords_;
48.135 - CompactBufferWriter sourcemap_;
48.136 - unsigned lastCodePosition_;
48.137 - unsigned firstLine_;
48.138 - StringTable strings_;
48.139 - Vector<Symbol *> locals_;
48.140 - Vector<Object *> objects_;
48.141 - unsigned loopDepth_;
48.142 - unsigned maxLoopDepth_;
48.143 -
48.144 - private:
48.145 - // The maximum size of a code object must be such that the distance between
48.146 - // two instructions fits into a signed, 31-bit integer. This ensures that
48.147 - // all code-bounded buffers (like the number of object literals or
48.148 - // safepoints) does not need to be bounds checked. It also means we can add
48.149 - // any two offsets and be guaranteed that they don't overflow.
48.150 - static const size_t MAX_LENGTH = INT_MAX / 2;
48.151 -
48.152 - private:
48.153 - bool growBuffer(size_t bytes);
48.154 -
48.155 - // Checking the return value is not necessary, since the inline buffer is
48.156 - // used as a ballast.
48.157 - bool ensure(size_t bytes) {
48.158 - if (buffer_pos_ + bytes > buffer_end_)
48.159 - return growBuffer(bytes);
48.160 - return true;
48.161 - }
48.162 -
48.163 - void writeUint8(unsigned value) {
48.164 - assert(value <= UCHAR_MAX);
48.165 - *buffer_pos_++ = value;
48.166 - }
48.167 - void writeFloat(float value) {
48.168 - *(float *)buffer_pos_ = value;
48.169 - buffer_pos_ += sizeof(float);
48.170 - }
48.171 - void writeInt32(int value) {
48.172 - *(int *)buffer_pos_ = value;
48.173 - buffer_pos_ += sizeof(int);
48.174 - }
48.175 - void writeUint32(unsigned value) {
48.176 - *(unsigned *)buffer_pos_ = value;
48.177 - buffer_pos_ += sizeof(unsigned);
48.178 - }
48.179 - void writeOp(Opcode op) {
48.180 - if (oom_)
48.181 - return;
48.182 -
48.183 - writeUint8(op);
48.184 - for (int i = 0; i < OpcodeInfo[op].nuses; i++)
48.185 - oopMap_.pop();
48.186 - for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
48.187 - oopMap_.append(false);
48.188 - if (oopMap_.length() > maxStackDepth_)
48.189 - maxStackDepth_ = oopMap_.length();
48.190 - }
48.191 - void writeObject(Object *obj) {
48.192 - assert(obj);
48.193 -
48.194 - writeUint32(objects_.length());
48.195 - if (!objects_.append(obj))
48.196 - oom_ = true;
48.197 - }
48.198 -
48.199 - int position() const {
48.200 - assert(buffer_pos_ - buffer_ < INT_MAX / 2);
48.201 - return int(buffer_pos_ - buffer_);
48.202 - }
48.203 -
48.204 - public:
48.205 - BytecodeEmitter();
48.206 - ~BytecodeEmitter();
48.207 -
48.208 - void accept(VirtualObjectVisitor *visitor);
48.209 -
48.210 - bytecode *buffer() const {
48.211 - return buffer_;
48.212 - }
48.213 - unsigned length() const {
48.214 - return unsigned(buffer_pos_ - buffer_);
48.215 - }
48.216 - bool oom() const {
48.217 - return oom_ || sourcemap_.oom();
48.218 - }
48.219 - unsigned stackDepth() const {
48.220 - return oopMap_.length();
48.221 - }
48.222 - unsigned maxStackDepth() const {
48.223 - return maxStackDepth_;
48.224 - }
48.225 -
48.226 - void drop(unsigned amt) {
48.227 - assert(amt <= stackDepth());
48.228 - for (unsigned i = 0; i < amt; i++)
48.229 - oopMap_.pop();
48.230 - }
48.231 -
48.232 - void note_position(const SourcePosition &pos);
48.233 - void setFirstLine(unsigned line) {
48.234 - assert(!sourcemap_.length());
48.235 - firstLine_ = line;
48.236 - }
48.237 -
48.238 - public:
48.239 - // A label represents a local control-flow target in the bytecode. A label
48.240 - // may be in three states:
48.241 - //
48.242 - // (1) Empty - the label is not used yet.
48.243 - // (2) Pending - the label has incoming jumps, but the actual location of
48.244 - // is not yet known. The list of jumps is threaded through
48.245 - // the four bytes reserved for each emitted jump target. In
48.246 - // this case, the offset field is the location of the most
48.247 - // recently emitted incoming jump.
48.248 - // (3) Bound - the label's position has been pinned.
48.249 - //
48.250 - // A jump can be emitted to a label in any state. Binding a label
48.251 - // immediately backpatches all pending incoming jumps. A label must be
48.252 - // bound if it is used.
48.253 - class Label
48.254 - {
48.255 - int offset_ : 31;
48.256 - bool bound_ : 1;
48.257 -
48.258 - void setOffset(int offset) {
48.259 - offset_ = offset;
48.260 - assert(offset_ == offset);
48.261 - }
48.262 -
48.263 - public:
48.264 - static const int INVALID_OFFSET = -1;
48.265 -
48.266 - public:
48.267 - Label()
48.268 - : offset_(INVALID_OFFSET),
48.269 - bound_(false)
48.270 - {
48.271 - }
48.272 - ~Label()
48.273 - {
48.274 - assert(bound_ || offset_ == INVALID_OFFSET);
48.275 - }
48.276 -
48.277 - bool bound() const {
48.278 - return bound_;
48.279 - }
48.280 - int offset() const {
48.281 - return offset_;
48.282 - }
48.283 - void bind(int offset) {
48.284 - assert(!bound_);
48.285 - setOffset(offset);
48.286 - bound_ = true;
48.287 - }
48.288 - int link(int offset) {
48.289 - assert(!bound_);
48.290 - int old = offset_;
48.291 - setOffset(offset);
48.292 - return old;
48.293 - }
48.294 - };
48.295 -
48.296 - private:
48.297 - int patchJumpAt(int at, int to) {
48.298 - assert(at >= 0 && at < position());
48.299 - int old = *(int *)(buffer_ + at + 1);
48.300 - *(int *)(buffer_ + at + 1) = (to - at);
48.301 - return old;
48.302 - }
48.303 -
48.304 - void singleByteOp(Opcode op) {
48.305 - assert(OpcodeInfo[op].length == 1);
48.306 - ensure(OpcodeInfo[op].length);
48.307 - writeOp(op);
48.308 - }
48.309 -
48.310 - // Mark a stack slot as having an object pointer.
48.311 - void markOop(unsigned depth, bool oop = true) {
48.312 - if (oom_)
48.313 - return;
48.314 - oopMap_[oopMap_.length() - depth] = oop;
48.315 - }
48.316 - bool getOop(unsigned depth) {
48.317 - if (oom_)
48.318 - return false;
48.319 - return oopMap_[oopMap_.length() - depth];
48.320 - }
48.321 -
48.322 - // Mark the current bytecode position as either re-entrant (meaning, it
48.323 - // can leave the interpreter or call to another function), or causing GC.
48.324 - // This will record which stack slots have objects and associate that
48.325 - // information with the current pc.
48.326 - void recordOops();
48.327 -
48.328 - public:
48.329 - void int_(int value) {
48.330 - ensure(OP_INT);
48.331 - writeOp(OP_INT);
48.332 - writeInt32(value);
48.333 - }
48.334 - void return_() {
48.335 - ensure(OP_RETURN);
48.336 - writeOp(OP_RETURN);
48.337 - }
48.338 - void getlocal(VariableSymbol *var);
48.339 - void setlocal(VariableSymbol *var);
48.340 - void getarg(VariableSymbol *var);
48.341 - void setarg(VariableSymbol *var);
48.342 -
48.343 - void j(Opcode op, Label *label) {
48.344 - // Since jumps can skip around the stream, do not try to do anything
48.345 - // in a potentially truncated state.
48.346 - if (oom())
48.347 - return;
48.348 -
48.349 - assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
48.350 - op == OP_CONTINUE || op == OP_BREAK);
48.351 - ensure(OP_JUMP_LENGTH);
48.352 -
48.353 - if (label->bound()) {
48.354 - // We can immediately emit this jump.
48.355 - int distance = label->offset() - position();
48.356 - writeOp(op);
48.357 - writeInt32(distance);
48.358 - } else {
48.359 - // We can't emit this jump yet. Add a placeholder.
48.360 - int old = label->link(position());
48.361 - writeOp(op);
48.362 - writeInt32(old);
48.363 - }
48.364 - }
48.365 - void bind(Label *label) {
48.366 - if (oom())
48.367 - return;
48.368 -
48.369 - assert(!label->bound());
48.370 -
48.371 - int offset = label->offset();
48.372 - while (offset != Label::INVALID_OFFSET)
48.373 - offset = patchJumpAt(offset, position());
48.374 -
48.375 - label->bind(position());
48.376 - }
48.377 - void jump(Label *label) {
48.378 - j(OP_JUMP, label);
48.379 - }
48.380 -
48.381 - void binary(Opcode op) {
48.382 - singleByteOp(op);
48.383 - }
48.384 - void unary(Opcode op) {
48.385 - singleByteOp(op);
48.386 - }
48.387 -
48.388 - void pop() {
48.389 - singleByteOp(OP_POP);
48.390 - }
48.391 - void stop() {
48.392 - singleByteOp(OP_STOP);
48.393 - }
48.394 - void call(Handle<FunctionType> fun, unsigned argc) {
48.395 - recordOops();
48.396 -
48.397 - if (fun->isNative()) {
48.398 - ensure(OP_CALLNATIVE_LENGTH);
48.399 - writeOp(OP_CALLNATIVE);
48.400 - writeUint32(argc);
48.401 - drop(argc + 1);
48.402 - } else {
48.403 - ensure(OP_CALL_LENGTH);
48.404 - writeOp(OP_CALL);
48.405 - drop(argc + 1);
48.406 -
48.407 - if (fun->returnType()->isVoid())
48.408 - drop(1);
48.409 - else if (fun->returnType()->isTraceable())
48.410 - markOop(1);
48.411 - }
48.412 - }
48.413 -
48.414 - void getelem(Type *type) {
48.415 - singleByteOp(OP_GETELEM);
48.416 -
48.417 - if (type->isTraceable())
48.418 - markOop(1);
48.419 - }
48.420 - void setelem(Type *type) {
48.421 - singleByteOp(OP_SETELEM);
48.422 - }
48.423 -
48.424 - void getfield(unsigned index, Type *type) {
48.425 - ensure(OP_GETFIELD_LENGTH);
48.426 - writeOp(OP_GETFIELD);
48.427 - writeUint32(index);
48.428 -
48.429 - if (type->isTraceable())
48.430 - markOop(1);
48.431 - }
48.432 - void setfield(unsigned index, Type *type) {
48.433 - ensure(OP_SETFIELD_LENGTH);
48.434 - writeOp(OP_SETFIELD);
48.435 - writeUint32(index);
48.436 -
48.437 - if (type->isTraceable())
48.438 - markOop(1);
48.439 - }
48.440 -
48.441 - int enterloop() {
48.442 - int offset = position();
48.443 -
48.444 - ensure(OP_ENTERLOOP);
48.445 - writeOp(OP_ENTERLOOP);
48.446 - writeUint8(0);
48.447 -
48.448 - loopDepth_++;
48.449 - if (loopDepth_ > maxLoopDepth_)
48.450 - maxLoopDepth_ = loopDepth_;
48.451 -
48.452 - return offset;
48.453 - }
48.454 - void leaveloop() {
48.455 - singleByteOp(OP_LEAVELOOP);
48.456 -
48.457 - assert(loopDepth_);
48.458 - loopDepth_--;
48.459 - }
48.460 - void setLoopUsesLifoStack(int pos) {
48.461 - assert(pos >= 0 && pos < position());
48.462 - assert(*(buffer() + pos) == OP_ENTERLOOP);
48.463 - *(buffer() + pos + 1) = 1;
48.464 - }
48.465 -
48.466 - void float_(float value) {
48.467 - ensure(OP_FLOAT_LENGTH);
48.468 - writeOp(OP_FLOAT);
48.469 - writeFloat(value);
48.470 - }
48.471 - void cvt_i2f() {
48.472 - singleByteOp(OP_CVT_I2F);
48.473 - }
48.474 - void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
48.475 - assert(op == OP_NEWFIXED ||
48.476 - op == OP_NEWEMPTY ||
48.477 - op == OP_NEWSIZED);
48.478 -
48.479 - recordOops();
48.480 - ensure(OpcodeInfo[op].length);
48.481 - writeOp(op);
48.482 - writeUint8(tenure);
48.483 - writeObject(map);
48.484 -
48.485 - if (op == OP_NEWSIZED)
48.486 - drop(map->type()->levels());
48.487 -
48.488 - markOop(1);
48.489 - }
48.490 - void newstruct(Handle<Map> map, Heap::Tenure tenure) {
48.491 - recordOops();
48.492 - ensure(OP_NEWSTRUCT_LENGTH);
48.493 - writeOp(OP_NEWSTRUCT);
48.494 - writeUint8(tenure);
48.495 - writeObject(map);
48.496 - markOop(1);
48.497 - }
48.498 - void deparray(ArrayMap *map) {
48.499 - recordOops();
48.500 - ensure(OP_DEPARRAY_LENGTH);
48.501 - writeOp(OP_DEPARRAY);
48.502 - writeObject(map);
48.503 - markOop(1);
48.504 - }
48.505 - void savelifo(unsigned slot) {
48.506 - ensure(OP_SAVELIFO_LENGTH);
48.507 - writeOp(OP_SAVELIFO);
48.508 - writeUint32(slot);
48.509 - }
48.510 - void unwindlifo(unsigned slot) {
48.511 - ensure(OP_UNWINDLIFO_LENGTH);
48.512 - writeOp(OP_UNWINDLIFO);
48.513 - writeUint32(slot);
48.514 - }
48.515 -
48.516 - void newref(VariableSymbol *var);
48.517 -
48.518 - void slotref_lifo() {
48.519 - recordOops();
48.520 - singleByteOp(OP_SLOTREF_LIFO);
48.521 - markOop(1);
48.522 - }
48.523 - void getref(Type *type) {
48.524 - if (type->pod() == PrimitiveType_Int32) {
48.525 - singleByteOp(OP_GETREF_I);
48.526 - } else {
48.527 - assert(type->pod() == PrimitiveType_Float);
48.528 - singleByteOp(OP_GETREF_F);
48.529 - }
48.530 - }
48.531 - void setref(Type *type) {
48.532 - if (type->pod() == PrimitiveType_Int32) {
48.533 - singleByteOp(OP_SETREF_I);
48.534 - } else {
48.535 - assert(type->pod() == PrimitiveType_Float);
48.536 - singleByteOp(OP_SETREF_F);
48.537 - }
48.538 - }
48.539 - void object(Handle<Object> obj) {
48.540 - assert(obj);
48.541 -
48.542 - ensure(OP_OBJECT_LENGTH);
48.543 - writeOp(OP_OBJECT);
48.544 - writeObject(obj);
48.545 - markOop(1);
48.546 - }
48.547 - void duparray() {
48.548 - singleByteOp(OP_DUPARRAY);
48.549 - markOop(1);
48.550 - }
48.551 - void copyarray() {
48.552 - singleByteOp(OP_COPYARRAY);
48.553 - markOop(1);
48.554 - }
48.555 - void copystruct() {
48.556 - singleByteOp(OP_COPYSTRUCT);
48.557 - markOop(1);
48.558 - }
48.559 - void sizeof_() {
48.560 - singleByteOp(OP_SIZEOF);
48.561 - }
48.562 -
48.563 - void dup() {
48.564 - bool oop = getOop(1);
48.565 - singleByteOp(OP_DUP);
48.566 - markOop(1, oop);
48.567 - }
48.568 - void dup2() {
48.569 - bool oop2 = getOop(2);
48.570 - bool oop1 = getOop(1);
48.571 -
48.572 - singleByteOp(OP_DUP2);
48.573 -
48.574 - markOop(2, oop2);
48.575 - markOop(1, oop1);
48.576 - }
48.577 - void swap() {
48.578 - bool oop2 = getOop(2);
48.579 - bool oop1 = getOop(1);
48.580 -
48.581 - singleByteOp(OP_SWAP);
48.582 -
48.583 - markOop(2, oop1);
48.584 - markOop(1, oop2);
48.585 - }
48.586 - void roll3() {
48.587 - bool oop3 = getOop(3);
48.588 - bool oop2 = getOop(2);
48.589 - bool oop1 = getOop(1);
48.590 -
48.591 - singleByteOp(OP_ROLL3);
48.592 -
48.593 - markOop(3, oop2);
48.594 - markOop(2, oop1);
48.595 - markOop(1, oop3);
48.596 - }
48.597 - void pick2() {
48.598 - bool oop2 = getOop(2);
48.599 - bool oop1 = getOop(1);
48.600 -
48.601 - singleByteOp(OP_PICK2);
48.602 -
48.603 - markOop(3, oop2);
48.604 - markOop(2, oop1);
48.605 - markOop(1, oop2);
48.606 - }
48.607 - void pick3() {
48.608 - bool oop3 = getOop(3);
48.609 - bool oop2 = getOop(2);
48.610 - bool oop1 = getOop(1);
48.611 -
48.612 - singleByteOp(OP_PICK3);
48.613 -
48.614 - markOop(4, oop3);
48.615 - markOop(3, oop2);
48.616 - markOop(2, oop1);
48.617 - markOop(1, oop3);
48.618 - }
48.619 -
48.620 - void returnvoid() {
48.621 - singleByteOp(OP_RETURNVOID);
48.622 - }
48.623 - void bitnot() {
48.624 - singleByteOp(OP_BITNOT);
48.625 - }
48.626 - void not_() {
48.627 - singleByteOp(OP_NOT);
48.628 - }
48.629 - void not_f() {
48.630 - singleByteOp(OP_NOT_F);
48.631 - }
48.632 - void neg() {
48.633 - singleByteOp(OP_NEG);
48.634 - }
48.635 - void neg_f() {
48.636 - singleByteOp(OP_NEG_F);
48.637 - }
48.638 - void true_() {
48.639 - singleByteOp(OP_TRUE);
48.640 - }
48.641 - void false_() {
48.642 - singleByteOp(OP_FALSE);
48.643 - }
48.644 -
48.645 - unsigned addString(Handle<String> name) {
48.646 - unsigned index;
48.647 - if (!strings_.add(name, &index)) {
48.648 - oom_ |= true;
48.649 - return 0;
48.650 - }
48.651 - return index;
48.652 - }
48.653 -
48.654 - void getglobal(Symbol *sym);
48.655 - void setglobal(Symbol *sym);
48.656 -
48.657 - void public_() {
48.658 - recordOops();
48.659 - singleByteOp(OP_PUBLIC);
48.660 - }
48.661 -
48.662 - void bitcast(Type *type) {
48.663 - ensure(OP_BITCAST_LENGTH);
48.664 - writeOp(OP_BITCAST);
48.665 - writeObject(type);
48.666 - }
48.667 -
48.668 - void tableswitch(int low, int high, Label *def, Label **labels) {
48.669 - unsigned tablesize = TableSwitchEntries(low, high);
48.670 - assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
48.671 -
48.672 - ensure(OP_TABLESWITCH_LENGTH);
48.673 - writeOp(OP_TABLESWITCH);
48.674 - writeInt32(low);
48.675 - writeInt32(high);
48.676 - jump(def);
48.677 -
48.678 - // When labels are patched, we assume each position is a jump. Rather
48.679 - // than hack position offsets to make labels work without actual
48.680 - // incoming jumps, we emit a jump inline.
48.681 - for (unsigned i = 0; i < tablesize; i++)
48.682 - jump(labels[i]);
48.683 - }
48.684 -
48.685 - void import(unsigned index) {
48.686 - ensure(OP_IMPORT_LENGTH);
48.687 - writeOp(OP_IMPORT);
48.688 - writeUint32(index);
48.689 - markOop(1);
48.690 - }
48.691 -
48.692 - bool allocate(VariableSymbol *sym);
48.693 -
48.694 - Code *finish();
48.695 -
48.696 - // Helpers.
48.697 -#if 0
48.698 - void get(Variable *var) {
48.699 - if (var->location() == Variable::STACK) {
48.700 - getlocal(var);
48.701 - } else {
48.702 - assert(var->location() == Variable::PARAMETER);
48.703 - getarg(var);
48.704 - }
48.705 - }
48.706 - void set(Variable *var) {
48.707 - assert(!var->type()->isReference());
48.708 - if (var->location() == Variable::STACK) {
48.709 - setlocal(var);
48.710 - } else {
48.711 - assert(var->location() == Variable::PARAMETER);
48.712 - setarg(var);
48.713 - }
48.714 - }
48.715 -#endif
48.716 -};
48.717 -
48.718 -}
48.719 -
48.720 -#endif // _include_bytecode_emitter_h_
48.721 +/* vim: set ts=4 sw=4 tw=99 et:
48.722 + *
48.723 + * Copyright (C) 2012 David Anderson
48.724 + *
48.725 + * This file is part of JITCraft.
48.726 + *
48.727 + * JITCraft is free software: you can redistribute it and/or modify it under
48.728 + * the terms of the GNU General Public License as published by the Free
48.729 + * Software Foundation, either version 3 of the License, or (at your option)
48.730 + * any later version.
48.731 + *
48.732 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
48.733 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
48.734 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
48.735 + *
48.736 + * You should have received a copy of the GNU General Public License along with
48.737 + * JITCraft. If not, see http://www.gnu.org/licenses/.
48.738 + */
48.739 +#ifndef _include_bytecode_emitter_h_
48.740 +#define _include_bytecode_emitter_h_
48.741 +
48.742 +#include <assert.h>
48.743 +#include <limits.h>
48.744 +#include "../Opcodes.h"
48.745 +#include "../Handles.h"
48.746 +#include "../CompactBuffer.h"
48.747 +#include "../Array.h"
48.748 +#include "../HashTable.h"
48.749 +#include "../VirtualObjectVisitor.h"
48.750 +
48.751 +namespace ke {
48.752 +
48.753 +// An overarching note on overflows: Though we should use CheckedInt, we rely
48.754 +// on a source-length cap covering all possible overflow checks. As long as
48.755 +// the source length is capped to INT_MAX, the number of AST nodes will be
48.756 +// strictly beneath that cap, and so to will most things generated by the
48.757 +// AST. For example, local and argument counts, number of functions, fields
48.758 +// in a struct, et cetera. Not everything can be covered by this cap: the
48.759 +// stack depth, number of bytecodes for example. In these cases we explicitly
48.760 +// test for overflow of INT_MAX and in other cases we assert.
48.761 +//
48.762 +// In the future, we should of course use a checked int wrapper.
48.763 +
48.764 +class Type;
48.765 +class Map;
48.766 +class ArrayMap;
48.767 +class Symbol;
48.768 +class VariableSymbol;
48.769 +
48.770 +struct OopRecord
48.771 +{
48.772 + unsigned depth;
48.773 + unsigned offset;
48.774 + Vector<bool> slots;
48.775 +
48.776 + OopRecord(unsigned length, unsigned offset)
48.777 + : depth(length),
48.778 + offset(offset)
48.779 + {
48.780 + }
48.781 +};
48.782 +
48.783 +class StringTable
48.784 +{
48.785 + struct Entry
48.786 + {
48.787 + String *string;
48.788 + unsigned index;
48.789 +
48.790 + Entry()
48.791 + : string(NULL),
48.792 + index(0)
48.793 + {
48.794 + }
48.795 +
48.796 + Entry(String *string, unsigned index)
48.797 + : string(string),
48.798 + index(index)
48.799 + {
48.800 + }
48.801 + };
48.802 +
48.803 + struct Policy
48.804 + {
48.805 + typedef Entry Payload;
48.806 +
48.807 + static uint32 hash(String *string) {
48.808 + return HashPointer(string);
48.809 + }
48.810 +
48.811 + static bool matches(String *key, Entry &e) {
48.812 + return key == e.string;
48.813 + }
48.814 + };
48.815 +
48.816 + typedef HashTable<Policy, ZoneAllocatorPolicy> Set;
48.817 +
48.818 + public:
48.819 + StringTable();
48.820 + bool initialize();
48.821 + void accept(VirtualObjectVisitor *visitor);
48.822 +
48.823 + bool add(Handle<String> name, unsigned *indexp);
48.824 + size_t stringCount() const {
48.825 + return strings_.length();
48.826 + }
48.827 + String *stringAt(size_t i) const {
48.828 + return strings_[i].string;
48.829 + }
48.830 +
48.831 + private:
48.832 + Set set_;
48.833 + Vector<Entry> strings_;
48.834 + bool initialized_;
48.835 +};
48.836 +
48.837 +// The bytecode emitter assists in building Code objects, by emitting opcodes
48.838 +// and tracking stack information. Since the SemA creates temporary pool/root
48.839 +// scopes, we cannot use ScopedRoot or PoolObjects. Instead, BCE gets a
48.840 +// special marking function.
48.841 +class BytecodeEmitter : public AutoRooted
48.842 +{
48.843 + private:
48.844 + bytecode *buffer_;
48.845 + bytecode *buffer_pos_;
48.846 + bytecode *buffer_end_;
48.847 + bytecode inline_buffer_[512];
48.848 + bool oom_;
48.849 + unsigned maxStackDepth_;
48.850 + Vector<bool> oopMap_;
48.851 + Vector<OopRecord *> oopRecords_;
48.852 + CompactBufferWriter sourcemap_;
48.853 + unsigned lastCodePosition_;
48.854 + unsigned firstLine_;
48.855 + StringTable strings_;
48.856 + Vector<Symbol *> locals_;
48.857 + Vector<Object *> objects_;
48.858 + unsigned loopDepth_;
48.859 + unsigned maxLoopDepth_;
48.860 +
48.861 + private:
48.862 + // The maximum size of a code object must be such that the distance between
48.863 + // two instructions fits into a signed, 31-bit integer. This ensures that
48.864 + // all code-bounded buffers (like the number of object literals or
48.865 + // safepoints) does not need to be bounds checked. It also means we can add
48.866 + // any two offsets and be guaranteed that they don't overflow.
48.867 + static const size_t MAX_LENGTH = INT_MAX / 2;
48.868 +
48.869 + private:
48.870 + bool growBuffer(size_t bytes);
48.871 +
48.872 + // Checking the return value is not necessary, since the inline buffer is
48.873 + // used as a ballast.
48.874 + bool ensure(size_t bytes) {
48.875 + if (buffer_pos_ + bytes > buffer_end_)
48.876 + return growBuffer(bytes);
48.877 + return true;
48.878 + }
48.879 +
48.880 + void writeUint8(unsigned value) {
48.881 + assert(value <= UCHAR_MAX);
48.882 + *buffer_pos_++ = value;
48.883 + }
48.884 + void writeFloat(float value) {
48.885 + *(float *)buffer_pos_ = value;
48.886 + buffer_pos_ += sizeof(float);
48.887 + }
48.888 + void writeInt32(int value) {
48.889 + *(int *)buffer_pos_ = value;
48.890 + buffer_pos_ += sizeof(int);
48.891 + }
48.892 + void writeUint32(unsigned value) {
48.893 + *(unsigned *)buffer_pos_ = value;
48.894 + buffer_pos_ += sizeof(unsigned);
48.895 + }
48.896 + void writeOp(Opcode op) {
48.897 + if (oom_)
48.898 + return;
48.899 +
48.900 + writeUint8(op);
48.901 + for (int i = 0; i < OpcodeInfo[op].nuses; i++)
48.902 + oopMap_.pop();
48.903 + for (int i = 0; i < OpcodeInfo[op].ndefs; i++)
48.904 + oopMap_.append(false);
48.905 + if (oopMap_.length() > maxStackDepth_)
48.906 + maxStackDepth_ = oopMap_.length();
48.907 + }
48.908 + void writeObject(Object *obj) {
48.909 + assert(obj);
48.910 +
48.911 + writeUint32(objects_.length());
48.912 + if (!objects_.append(obj))
48.913 + oom_ = true;
48.914 + }
48.915 +
48.916 + int position() const {
48.917 + assert(buffer_pos_ - buffer_ < INT_MAX / 2);
48.918 + return int(buffer_pos_ - buffer_);
48.919 + }
48.920 +
48.921 + public:
48.922 + BytecodeEmitter();
48.923 + ~BytecodeEmitter();
48.924 +
48.925 + void accept(VirtualObjectVisitor *visitor);
48.926 +
48.927 + bytecode *buffer() const {
48.928 + return buffer_;
48.929 + }
48.930 + unsigned length() const {
48.931 + return unsigned(buffer_pos_ - buffer_);
48.932 + }
48.933 + bool oom() const {
48.934 + return oom_ || sourcemap_.oom();
48.935 + }
48.936 + unsigned stackDepth() const {
48.937 + return oopMap_.length();
48.938 + }
48.939 + unsigned maxStackDepth() const {
48.940 + return maxStackDepth_;
48.941 + }
48.942 +
48.943 + void drop(unsigned amt) {
48.944 + assert(amt <= stackDepth());
48.945 + for (unsigned i = 0; i < amt; i++)
48.946 + oopMap_.pop();
48.947 + }
48.948 +
48.949 + void note_position(const SourcePosition &pos);
48.950 + void setFirstLine(unsigned line) {
48.951 + assert(!sourcemap_.length());
48.952 + firstLine_ = line;
48.953 + }
48.954 +
48.955 + public:
48.956 + // A label represents a local control-flow target in the bytecode. A label
48.957 + // may be in three states:
48.958 + //
48.959 + // (1) Empty - the label is not used yet.
48.960 + // (2) Pending - the label has incoming jumps, but the actual location of
48.961 + // is not yet known. The list of jumps is threaded through
48.962 + // the four bytes reserved for each emitted jump target. In
48.963 + // this case, the offset field is the location of the most
48.964 + // recently emitted incoming jump.
48.965 + // (3) Bound - the label's position has been pinned.
48.966 + //
48.967 + // A jump can be emitted to a label in any state. Binding a label
48.968 + // immediately backpatches all pending incoming jumps. A label must be
48.969 + // bound if it is used.
48.970 + class Label
48.971 + {
48.972 + int offset_ : 31;
48.973 + bool bound_ : 1;
48.974 +
48.975 + void setOffset(int offset) {
48.976 + offset_ = offset;
48.977 + assert(offset_ == offset);
48.978 + }
48.979 +
48.980 + public:
48.981 + static const int INVALID_OFFSET = -1;
48.982 +
48.983 + public:
48.984 + Label()
48.985 + : offset_(INVALID_OFFSET),
48.986 + bound_(false)
48.987 + {
48.988 + }
48.989 + ~Label()
48.990 + {
48.991 + assert(bound_ || offset_ == INVALID_OFFSET);
48.992 + }
48.993 +
48.994 + bool bound() const {
48.995 + return bound_;
48.996 + }
48.997 + int offset() const {
48.998 + return offset_;
48.999 + }
48.1000 + void bind(int offset) {
48.1001 + assert(!bound_);
48.1002 + setOffset(offset);
48.1003 + bound_ = true;
48.1004 + }
48.1005 + int link(int offset) {
48.1006 + assert(!bound_);
48.1007 + int old = offset_;
48.1008 + setOffset(offset);
48.1009 + return old;
48.1010 + }
48.1011 + };
48.1012 +
48.1013 + private:
48.1014 + int patchJumpAt(int at, int to) {
48.1015 + assert(at >= 0 && at < position());
48.1016 + int old = *(int *)(buffer_ + at + 1);
48.1017 + *(int *)(buffer_ + at + 1) = (to - at);
48.1018 + return old;
48.1019 + }
48.1020 +
48.1021 + void singleByteOp(Opcode op) {
48.1022 + assert(OpcodeInfo[op].length == 1);
48.1023 + ensure(OpcodeInfo[op].length);
48.1024 + writeOp(op);
48.1025 + }
48.1026 +
48.1027 + // Mark a stack slot as having an object pointer.
48.1028 + void markOop(unsigned depth, bool oop = true) {
48.1029 + if (oom_)
48.1030 + return;
48.1031 + oopMap_[oopMap_.length() - depth] = oop;
48.1032 + }
48.1033 + bool getOop(unsigned depth) {
48.1034 + if (oom_)
48.1035 + return false;
48.1036 + return oopMap_[oopMap_.length() - depth];
48.1037 + }
48.1038 +
48.1039 + // Mark the current bytecode position as either re-entrant (meaning, it
48.1040 + // can leave the interpreter or call to another function), or causing GC.
48.1041 + // This will record which stack slots have objects and associate that
48.1042 + // information with the current pc.
48.1043 + void recordOops();
48.1044 +
48.1045 + public:
48.1046 + void int_(int value) {
48.1047 + ensure(OP_INT);
48.1048 + writeOp(OP_INT);
48.1049 + writeInt32(value);
48.1050 + }
48.1051 + void return_() {
48.1052 + ensure(OP_RETURN);
48.1053 + writeOp(OP_RETURN);
48.1054 + }
48.1055 + void getlocal(VariableSymbol *var);
48.1056 + void setlocal(VariableSymbol *var);
48.1057 + void getarg(VariableSymbol *var);
48.1058 + void setarg(VariableSymbol *var);
48.1059 +
48.1060 + void j(Opcode op, Label *label) {
48.1061 + // Since jumps can skip around the stream, do not try to do anything
48.1062 + // in a potentially truncated state.
48.1063 + if (oom())
48.1064 + return;
48.1065 +
48.1066 + assert(op == OP_JT || op == OP_JF || op == OP_JUMP ||
48.1067 + op == OP_CONTINUE || op == OP_BREAK);
48.1068 + ensure(OP_JUMP_LENGTH);
48.1069 +
48.1070 + if (label->bound()) {
48.1071 + // We can immediately emit this jump.
48.1072 + int distance = label->offset() - position();
48.1073 + writeOp(op);
48.1074 + writeInt32(distance);
48.1075 + } else {
48.1076 + // We can't emit this jump yet. Add a placeholder.
48.1077 + int old = label->link(position());
48.1078 + writeOp(op);
48.1079 + writeInt32(old);
48.1080 + }
48.1081 + }
48.1082 + void bind(Label *label) {
48.1083 + if (oom())
48.1084 + return;
48.1085 +
48.1086 + assert(!label->bound());
48.1087 +
48.1088 + int offset = label->offset();
48.1089 + while (offset != Label::INVALID_OFFSET)
48.1090 + offset = patchJumpAt(offset, position());
48.1091 +
48.1092 + label->bind(position());
48.1093 + }
48.1094 + void jump(Label *label) {
48.1095 + j(OP_JUMP, label);
48.1096 + }
48.1097 +
48.1098 + void binary(Opcode op) {
48.1099 + singleByteOp(op);
48.1100 + }
48.1101 + void unary(Opcode op) {
48.1102 + singleByteOp(op);
48.1103 + }
48.1104 +
48.1105 + void pop() {
48.1106 + singleByteOp(OP_POP);
48.1107 + }
48.1108 + void stop() {
48.1109 + singleByteOp(OP_STOP);
48.1110 + }
48.1111 + void call(Handle<FunctionType> fun, unsigned argc) {
48.1112 + recordOops();
48.1113 +
48.1114 + if (fun->isNative()) {
48.1115 + ensure(OP_CALLNATIVE_LENGTH);
48.1116 + writeOp(OP_CALLNATIVE);
48.1117 + writeUint32(argc);
48.1118 + drop(argc + 1);
48.1119 + } else {
48.1120 + ensure(OP_CALL_LENGTH);
48.1121 + writeOp(OP_CALL);
48.1122 + drop(argc + 1);
48.1123 +
48.1124 + if (fun->returnType()->isVoid())
48.1125 + drop(1);
48.1126 + else if (fun->returnType()->isTraceable())
48.1127 + markOop(1);
48.1128 + }
48.1129 + }
48.1130 +
48.1131 + void getelem(Type *type) {
48.1132 + singleByteOp(OP_GETELEM);
48.1133 +
48.1134 + if (type->isTraceable())
48.1135 + markOop(1);
48.1136 + }
48.1137 + void setelem(Type *type) {
48.1138 + singleByteOp(OP_SETELEM);
48.1139 + }
48.1140 +
48.1141 + void getfield(unsigned index, Type *type) {
48.1142 + ensure(OP_GETFIELD_LENGTH);
48.1143 + writeOp(OP_GETFIELD);
48.1144 + writeUint32(index);
48.1145 +
48.1146 + if (type->isTraceable())
48.1147 + markOop(1);
48.1148 + }
48.1149 + void setfield(unsigned index, Type *type) {
48.1150 + ensure(OP_SETFIELD_LENGTH);
48.1151 + writeOp(OP_SETFIELD);
48.1152 + writeUint32(index);
48.1153 +
48.1154 + if (type->isTraceable())
48.1155 + markOop(1);
48.1156 + }
48.1157 +
48.1158 + int enterloop() {
48.1159 + int offset = position();
48.1160 +
48.1161 + ensure(OP_ENTERLOOP);
48.1162 + writeOp(OP_ENTERLOOP);
48.1163 + writeUint8(0);
48.1164 +
48.1165 + loopDepth_++;
48.1166 + if (loopDepth_ > maxLoopDepth_)
48.1167 + maxLoopDepth_ = loopDepth_;
48.1168 +
48.1169 + return offset;
48.1170 + }
48.1171 + void leaveloop() {
48.1172 + singleByteOp(OP_LEAVELOOP);
48.1173 +
48.1174 + assert(loopDepth_);
48.1175 + loopDepth_--;
48.1176 + }
48.1177 + void setLoopUsesLifoStack(int pos) {
48.1178 + assert(pos >= 0 && pos < position());
48.1179 + assert(*(buffer() + pos) == OP_ENTERLOOP);
48.1180 + *(buffer() + pos + 1) = 1;
48.1181 + }
48.1182 +
48.1183 + void float_(float value) {
48.1184 + ensure(OP_FLOAT_LENGTH);
48.1185 + writeOp(OP_FLOAT);
48.1186 + writeFloat(value);
48.1187 + }
48.1188 + void cvt_i2f() {
48.1189 + singleByteOp(OP_CVT_I2F);
48.1190 + }
48.1191 + void newarray(Opcode op, Handle<ArrayMap> map, Heap::Tenure tenure) {
48.1192 + assert(op == OP_NEWFIXED ||
48.1193 + op == OP_NEWEMPTY ||
48.1194 + op == OP_NEWSIZED);
48.1195 +
48.1196 + recordOops();
48.1197 + ensure(OpcodeInfo[op].length);
48.1198 + writeOp(op);
48.1199 + writeUint8(tenure);
48.1200 + writeObject(map);
48.1201 +
48.1202 + if (op == OP_NEWSIZED)
48.1203 + drop(map->type()->levels());
48.1204 +
48.1205 + markOop(1);
48.1206 + }
48.1207 + void newstruct(Handle<Map> map, Heap::Tenure tenure) {
48.1208 + recordOops();
48.1209 + ensure(OP_NEWSTRUCT_LENGTH);
48.1210 + writeOp(OP_NEWSTRUCT);
48.1211 + writeUint8(tenure);
48.1212 + writeObject(map);
48.1213 + markOop(1);
48.1214 + }
48.1215 + void deparray(ArrayMap *map) {
48.1216 + recordOops();
48.1217 + ensure(OP_DEPARRAY_LENGTH);
48.1218 + writeOp(OP_DEPARRAY);
48.1219 + writeObject(map);
48.1220 + markOop(1);
48.1221 + }
48.1222 + void savelifo(unsigned slot) {
48.1223 + ensure(OP_SAVELIFO_LENGTH);
48.1224 + writeOp(OP_SAVELIFO);
48.1225 + writeUint32(slot);
48.1226 + }
48.1227 + void unwindlifo(unsigned slot) {
48.1228 + ensure(OP_UNWINDLIFO_LENGTH);
48.1229 + writeOp(OP_UNWINDLIFO);
48.1230 + writeUint32(slot);
48.1231 + }
48.1232 +
48.1233 + void newref(VariableSymbol *var);
48.1234 +
48.1235 + void slotref_lifo() {
48.1236 + recordOops();
48.1237 + singleByteOp(OP_SLOTREF_LIFO);
48.1238 + markOop(1);
48.1239 + }
48.1240 + void getref(Type *type) {
48.1241 + if (type->pod() == PrimitiveType_Int32) {
48.1242 + singleByteOp(OP_GETREF_I);
48.1243 + } else {
48.1244 + assert(type->pod() == PrimitiveType_Float);
48.1245 + singleByteOp(OP_GETREF_F);
48.1246 + }
48.1247 + }
48.1248 + void setref(Type *type) {
48.1249 + if (type->pod() == PrimitiveType_Int32) {
48.1250 + singleByteOp(OP_SETREF_I);
48.1251 + } else {
48.1252 + assert(type->pod() == PrimitiveType_Float);
48.1253 + singleByteOp(OP_SETREF_F);
48.1254 + }
48.1255 + }
48.1256 + void object(Handle<Object> obj) {
48.1257 + assert(obj);
48.1258 +
48.1259 + ensure(OP_OBJECT_LENGTH);
48.1260 + writeOp(OP_OBJECT);
48.1261 + writeObject(obj);
48.1262 + markOop(1);
48.1263 + }
48.1264 + void duparray() {
48.1265 + singleByteOp(OP_DUPARRAY);
48.1266 + markOop(1);
48.1267 + }
48.1268 + void copyarray() {
48.1269 + singleByteOp(OP_COPYARRAY);
48.1270 + markOop(1);
48.1271 + }
48.1272 + void copystruct() {
48.1273 + singleByteOp(OP_COPYSTRUCT);
48.1274 + markOop(1);
48.1275 + }
48.1276 + void sizeof_() {
48.1277 + singleByteOp(OP_SIZEOF);
48.1278 + }
48.1279 +
48.1280 + void dup() {
48.1281 + bool oop = getOop(1);
48.1282 + singleByteOp(OP_DUP);
48.1283 + markOop(1, oop);
48.1284 + }
48.1285 + void dup2() {
48.1286 + bool oop2 = getOop(2);
48.1287 + bool oop1 = getOop(1);
48.1288 +
48.1289 + singleByteOp(OP_DUP2);
48.1290 +
48.1291 + markOop(2, oop2);
48.1292 + markOop(1, oop1);
48.1293 + }
48.1294 + void swap() {
48.1295 + bool oop2 = getOop(2);
48.1296 + bool oop1 = getOop(1);
48.1297 +
48.1298 + singleByteOp(OP_SWAP);
48.1299 +
48.1300 + markOop(2, oop1);
48.1301 + markOop(1, oop2);
48.1302 + }
48.1303 + void roll3() {
48.1304 + bool oop3 = getOop(3);
48.1305 + bool oop2 = getOop(2);
48.1306 + bool oop1 = getOop(1);
48.1307 +
48.1308 + singleByteOp(OP_ROLL3);
48.1309 +
48.1310 + markOop(3, oop2);
48.1311 + markOop(2, oop1);
48.1312 + markOop(1, oop3);
48.1313 + }
48.1314 + void pick2() {
48.1315 + bool oop2 = getOop(2);
48.1316 + bool oop1 = getOop(1);
48.1317 +
48.1318 + singleByteOp(OP_PICK2);
48.1319 +
48.1320 + markOop(3, oop2);
48.1321 + markOop(2, oop1);
48.1322 + markOop(1, oop2);
48.1323 + }
48.1324 + void pick3() {
48.1325 + bool oop3 = getOop(3);
48.1326 + bool oop2 = getOop(2);
48.1327 + bool oop1 = getOop(1);
48.1328 +
48.1329 + singleByteOp(OP_PICK3);
48.1330 +
48.1331 + markOop(4, oop3);
48.1332 + markOop(3, oop2);
48.1333 + markOop(2, oop1);
48.1334 + markOop(1, oop3);
48.1335 + }
48.1336 +
48.1337 + void returnvoid() {
48.1338 + singleByteOp(OP_RETURNVOID);
48.1339 + }
48.1340 + void bitnot() {
48.1341 + singleByteOp(OP_BITNOT);
48.1342 + }
48.1343 + void not_() {
48.1344 + singleByteOp(OP_NOT);
48.1345 + }
48.1346 + void not_f() {
48.1347 + singleByteOp(OP_NOT_F);
48.1348 + }
48.1349 + void neg() {
48.1350 + singleByteOp(OP_NEG);
48.1351 + }
48.1352 + void neg_f() {
48.1353 + singleByteOp(OP_NEG_F);
48.1354 + }
48.1355 + void true_() {
48.1356 + singleByteOp(OP_TRUE);
48.1357 + }
48.1358 + void false_() {
48.1359 + singleByteOp(OP_FALSE);
48.1360 + }
48.1361 +
48.1362 + unsigned addString(Handle<String> name) {
48.1363 + unsigned index;
48.1364 + if (!strings_.add(name, &index)) {
48.1365 + oom_ |= true;
48.1366 + return 0;
48.1367 + }
48.1368 + return index;
48.1369 + }
48.1370 +
48.1371 + void getglobal(Symbol *sym);
48.1372 + void setglobal(Symbol *sym);
48.1373 +
48.1374 + void public_() {
48.1375 + recordOops();
48.1376 + singleByteOp(OP_PUBLIC);
48.1377 + }
48.1378 +
48.1379 + void bitcast(Type *type) {
48.1380 + ensure(OP_BITCAST_LENGTH);
48.1381 + writeOp(OP_BITCAST);
48.1382 + writeObject(type);
48.1383 + }
48.1384 +
48.1385 + void tableswitch(int low, int high, Label *def, Label **labels) {
48.1386 + unsigned tablesize = TableSwitchEntries(low, high);
48.1387 + assert(tablesize <= MAX_TABLESWITCH_ENTRIES);
48.1388 +
48.1389 + ensure(OP_TABLESWITCH_LENGTH);
48.1390 + writeOp(OP_TABLESWITCH);
48.1391 + writeInt32(low);
48.1392 + writeInt32(high);
48.1393 + jump(def);
48.1394 +
48.1395 + // When labels are patched, we assume each position is a jump. Rather
48.1396 + // than hack position offsets to make labels work without actual
48.1397 + // incoming jumps, we emit a jump inline.
48.1398 + for (unsigned i = 0; i < tablesize; i++)
48.1399 + jump(labels[i]);
48.1400 + }
48.1401 +
48.1402 + void import(unsigned index) {
48.1403 + ensure(OP_IMPORT_LENGTH);
48.1404 + writeOp(OP_IMPORT);
48.1405 + writeUint32(index);
48.1406 + markOop(1);
48.1407 + }
48.1408 +
48.1409 + bool allocate(VariableSymbol *sym);
48.1410 +
48.1411 + Code *finish();
48.1412 +
48.1413 + // Helpers.
48.1414 +#if 0
48.1415 + void get(Variable *var) {
48.1416 + if (var->location() == Variable::STACK) {
48.1417 + getlocal(var);
48.1418 + } else {
48.1419 + assert(var->location() == Variable::PARAMETER);
48.1420 + getarg(var);
48.1421 + }
48.1422 + }
48.1423 + void set(Variable *var) {
48.1424 + assert(!var->type()->isReference());
48.1425 + if (var->location() == Variable::STACK) {
48.1426 + setlocal(var);
48.1427 + } else {
48.1428 + assert(var->location() == Variable::PARAMETER);
48.1429 + setarg(var);
48.1430 + }
48.1431 + }
48.1432 +#endif
48.1433 +};
48.1434 +
48.1435 +}
48.1436 +
48.1437 +#endif // _include_bytecode_emitter_h_
49.1 --- a/src/compiler/CompileContext.h Mon Jun 10 00:46:29 2013 +0100
49.2 +++ b/src/compiler/CompileContext.h Mon Jun 10 01:04:43 2013 +0100
49.3 @@ -1,170 +1,170 @@
49.4 -/*
49.5 - * Copyright (C) 2012 David Anderson
49.6 - *
49.7 - * This file is part of SourcePawn.
49.8 - *
49.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
49.10 - * the terms of the GNU General Public License as published by the Free
49.11 - * Software Foundation, either version 3 of the License, or (at your option)
49.12 - * any later version.
49.13 - *
49.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
49.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
49.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
49.17 - *
49.18 - * You should have received a copy of the GNU General Public License along with
49.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
49.20 - */
49.21 -#ifndef _include_jitcraft_compile_context_h_
49.22 -#define _include_jitcraft_compile_context_h_
49.23 -
49.24 -#include <stdarg.h>
49.25 -#include <string>
49.26 -#include "../Messages.h"
49.27 -#include "../PoolAllocator.h"
49.28 -#include "../Handles.h"
49.29 -#include "../Modules.h"
49.30 -#include "../Packages.h"
49.31 -
49.32 -namespace ke {
49.33 -
49.34 -class Zone;
49.35 -class ParseTree;
49.36 -class String;
49.37 -class ImportScope;
49.38 -class GlobalScope;
49.39 -struct SourcePosition;
49.40 -struct TranslationUnit;
49.41 -class ImportStatement;
49.42 -
49.43 -struct CompileError
49.44 -{
49.45 - CompileError()
49.46 - : message(NULL)
49.47 - {
49.48 - }
49.49 - CompileError(unsigned line, unsigned col, const char *message)
49.50 - : line(line),
49.51 - col(col),
49.52 - message(message)
49.53 - {
49.54 - }
49.55 -
49.56 - unsigned line;
49.57 - unsigned col;
49.58 - const char *message;
49.59 -};
49.60 -
49.61 -struct TranslationUnit : public PoolObject
49.62 -{
49.63 - TranslationUnit(Handle<Module> module)
49.64 - : tree_(NULL),
49.65 - importScope_(NULL),
49.66 - globalScope_(NULL),
49.67 - module_(module),
49.68 - enoughMemory_(true),
49.69 - dependencyFailed_(false)
49.70 - {
49.71 - }
49.72 -
49.73 - void destroy();
49.74 -
49.75 - ParseTree *tree_;
49.76 - PoolList<TranslationUnit *> dependents_;
49.77 - ImportScope *importScope_;
49.78 - GlobalScope *globalScope_;
49.79 - ScopedRoot<Module> module_;
49.80 -
49.81 - ParseTree *tree() const {
49.82 - return tree_;
49.83 - }
49.84 - PoolList<TranslationUnit *> &dependents() {
49.85 - return dependents_;
49.86 - }
49.87 - bool failed() const {
49.88 - return errors_.length() ||
49.89 - !enoughMemory_ ||
49.90 - dependencyFailed_;
49.91 - }
49.92 - void setImportScope(ImportScope *scope) {
49.93 - assert(!importScope_);
49.94 - importScope_ = scope;
49.95 - }
49.96 - void setGlobalScope(GlobalScope *scope) {
49.97 - assert(!globalScope_);
49.98 - globalScope_ = scope;
49.99 - }
49.100 - ImportScope *importScope() const {
49.101 - return importScope_;
49.102 - }
49.103 - GlobalScope *globalScope() const {
49.104 - return globalScope_;
49.105 - }
49.106 - Handle<Module> module() {
49.107 - return module_;
49.108 - }
49.109 -
49.110 - void setDependencyFailed() {
49.111 - dependencyFailed_ = true;
49.112 - }
49.113 - void setOutOfMemory() {
49.114 - enoughMemory_ = false;
49.115 - }
49.116 - void appendError(const char *report, unsigned line, unsigned col) {
49.117 - enoughMemory_ |= errors_.append(CompileError(line, col, report));
49.118 - }
49.119 - const Vector<CompileError> *errors() {
49.120 - return &errors_;
49.121 - }
49.122 -
49.123 - private:
49.124 - bool enoughMemory_;
49.125 - bool dependencyFailed_;
49.126 - Vector<CompileError> errors_;
49.127 -};
49.128 -
49.129 -class CompileContext
49.130 -{
49.131 - Zone *zone_;
49.132 - Vector<TranslationUnit *> units_;
49.133 - Vector<TranslationUnit *> unparsed_;
49.134 - TranslationUnit *active_;
49.135 -
49.136 - private:
49.137 - char *loadSource(Handle<Module> module, size_t *length);
49.138 - bool parse(TranslationUnit *unit);
49.139 - bool evaluateImports(TranslationUnit *unit);
49.140 - bool propagateFailure();
49.141 - bool add(Handle<Module> module);
49.142 -
49.143 - public:
49.144 - CompileContext(Zone *zone);
49.145 - ~CompileContext();
49.146 -
49.147 - bool initialize(Handle<Package> package, const char *name);
49.148 - bool compile();
49.149 - void enter(TranslationUnit *unit);
49.150 - void leave();
49.151 -
49.152 - void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
49.153 - void reportError(const SourcePosition &pos, Message msg, ...);
49.154 -};
49.155 -
49.156 -class AutoEnterCompileContext
49.157 -{
49.158 - CompileContext &cc_;
49.159 -
49.160 - public:
49.161 - AutoEnterCompileContext(CompileContext &cc, TranslationUnit *unit)
49.162 - : cc_(cc)
49.163 - {
49.164 - cc_.enter(unit);
49.165 - }
49.166 - ~AutoEnterCompileContext() {
49.167 - cc_.leave();
49.168 - }
49.169 -};
49.170 -
49.171 -} // namespace ke
49.172 -
49.173 -#endif // _include_jitcraft_compile_context_h_
49.174 +/*
49.175 + * Copyright (C) 2012 David Anderson
49.176 + *
49.177 + * This file is part of SourcePawn.
49.178 + *
49.179 + * SourcePawn is free software: you can redistribute it and/or modify it under
49.180 + * the terms of the GNU General Public License as published by the Free
49.181 + * Software Foundation, either version 3 of the License, or (at your option)
49.182 + * any later version.
49.183 + *
49.184 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
49.185 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
49.186 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
49.187 + *
49.188 + * You should have received a copy of the GNU General Public License along with
49.189 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
49.190 + */
49.191 +#ifndef _include_jitcraft_compile_context_h_
49.192 +#define _include_jitcraft_compile_context_h_
49.193 +
49.194 +#include <stdarg.h>
49.195 +#include <string>
49.196 +#include "../Messages.h"
49.197 +#include "../PoolAllocator.h"
49.198 +#include "../Handles.h"
49.199 +#include "../Modules.h"
49.200 +#include "../Packages.h"
49.201 +
49.202 +namespace ke {
49.203 +
49.204 +class Zone;
49.205 +class ParseTree;
49.206 +class String;
49.207 +class ImportScope;
49.208 +class GlobalScope;
49.209 +struct SourcePosition;
49.210 +struct TranslationUnit;
49.211 +class ImportStatement;
49.212 +
49.213 +struct CompileError
49.214 +{
49.215 + CompileError()
49.216 + : message(NULL)
49.217 + {
49.218 + }
49.219 + CompileError(unsigned line, unsigned col, const char *message)
49.220 + : line(line),
49.221 + col(col),
49.222 + message(message)
49.223 + {
49.224 + }
49.225 +
49.226 + unsigned line;
49.227 + unsigned col;
49.228 + const char *message;
49.229 +};
49.230 +
49.231 +struct TranslationUnit : public PoolObject
49.232 +{
49.233 + TranslationUnit(Handle<Module> module)
49.234 + : tree_(NULL),
49.235 + importScope_(NULL),
49.236 + globalScope_(NULL),
49.237 + module_(module),
49.238 + enoughMemory_(true),
49.239 + dependencyFailed_(false)
49.240 + {
49.241 + }
49.242 +
49.243 + void destroy();
49.244 +
49.245 + ParseTree *tree_;
49.246 + PoolList<TranslationUnit *> dependents_;
49.247 + ImportScope *importScope_;
49.248 + GlobalScope *globalScope_;
49.249 + ScopedRoot<Module> module_;
49.250 +
49.251 + ParseTree *tree() const {
49.252 + return tree_;
49.253 + }
49.254 + PoolList<TranslationUnit *> &dependents() {
49.255 + return dependents_;
49.256 + }
49.257 + bool failed() const {
49.258 + return errors_.length() ||
49.259 + !enoughMemory_ ||
49.260 + dependencyFailed_;
49.261 + }
49.262 + void setImportScope(ImportScope *scope) {
49.263 + assert(!importScope_);
49.264 + importScope_ = scope;
49.265 + }
49.266 + void setGlobalScope(GlobalScope *scope) {
49.267 + assert(!globalScope_);
49.268 + globalScope_ = scope;
49.269 + }
49.270 + ImportScope *importScope() const {
49.271 + return importScope_;
49.272 + }
49.273 + GlobalScope *globalScope() const {
49.274 + return globalScope_;
49.275 + }
49.276 + Handle<Module> module() {
49.277 + return module_;
49.278 + }
49.279 +
49.280 + void setDependencyFailed() {
49.281 + dependencyFailed_ = true;
49.282 + }
49.283 + void setOutOfMemory() {
49.284 + enoughMemory_ = false;
49.285 + }
49.286 + void appendError(const char *report, unsigned line, unsigned col) {
49.287 + enoughMemory_ |= errors_.append(CompileError(line, col, report));
49.288 + }
49.289 + const Vector<CompileError> *errors() {
49.290 + return &errors_;
49.291 + }
49.292 +
49.293 + private:
49.294 + bool enoughMemory_;
49.295 + bool dependencyFailed_;
49.296 + Vector<CompileError> errors_;
49.297 +};
49.298 +
49.299 +class CompileContext
49.300 +{
49.301 + Zone *zone_;
49.302 + Vector<TranslationUnit *> units_;
49.303 + Vector<TranslationUnit *> unparsed_;
49.304 + TranslationUnit *active_;
49.305 +
49.306 + private:
49.307 + char *loadSource(Handle<Module> module, size_t *length);
49.308 + bool parse(TranslationUnit *unit);
49.309 + bool evaluateImports(TranslationUnit *unit);
49.310 + bool propagateFailure();
49.311 + bool add(Handle<Module> module);
49.312 +
49.313 + public:
49.314 + CompileContext(Zone *zone);
49.315 + ~CompileContext();
49.316 +
49.317 + bool initialize(Handle<Package> package, const char *name);
49.318 + bool compile();
49.319 + void enter(TranslationUnit *unit);
49.320 + void leave();
49.321 +
49.322 + void reportErrorVa(const SourcePosition &pos, Message msg, va_list ap);
49.323 + void reportError(const SourcePosition &pos, Message msg, ...);
49.324 +};
49.325 +
49.326 +class AutoEnterCompileContext
49.327 +{
49.328 + CompileContext &cc_;
49.329 +
49.330 + public:
49.331 + AutoEnterCompileContext(CompileContext &cc, TranslationUnit *unit)
49.332 + : cc_(cc)
49.333 + {
49.334 + cc_.enter(unit);
49.335 + }
49.336 + ~AutoEnterCompileContext() {
49.337 + cc_.leave();
49.338 + }
49.339 +};
49.340 +
49.341 +} // namespace ke
49.342 +
49.343 +#endif // _include_jitcraft_compile_context_h_
50.1 --- a/src/compiler/ConstantEvaluator.cpp Mon Jun 10 00:46:29 2013 +0100
50.2 +++ b/src/compiler/ConstantEvaluator.cpp Mon Jun 10 01:04:43 2013 +0100
50.3 @@ -1,94 +1,94 @@
50.4 -/* vim: set ts=4 sw=4 tw=99 et:
50.5 - *
50.6 - * Copyright (C) 2012 David Anderson
50.7 - *
50.8 - * This file is part of SourcePawn.
50.9 - *
50.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
50.11 - * the terms of the GNU General Public License as published by the Free
50.12 - * Software Foundation, either version 3 of the License, or (at your option)
50.13 - * any later version.
50.14 - *
50.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
50.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
50.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
50.18 - *
50.19 - * You should have received a copy of the GNU General Public License along with
50.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
50.21 - */
50.22 -#include "AST.h"
50.23 -#include "ConstantEvaluator.h"
50.24 -#include "../Heap-inl.h"
50.25 -#include "../Handles-inl.h"
50.26 -
50.27 -using namespace ke;
50.28 -
50.29 -static inline bool
50.30 -EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
50.31 - BoxedPrimitive *out)
50.32 -{
50.33 - switch (kind) {
50.34 - case TOK_PLUS:
50.35 - *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
50.36 - return true;
50.37 -
50.38 - case TOK_SHL:
50.39 - *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
50.40 - return true;
50.41 -
50.42 - default:
50.43 - return false;
50.44 - }
50.45 -}
50.46 -
50.47 -static inline bool
50.48 -EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
50.49 -{
50.50 - switch (kind) {
50.51 - case TOK_MINUS:
50.52 - *out = BoxedPrimitive::Int(-inner.toInt());
50.53 - return true;
50.54 -
50.55 - default:
50.56 - return false;
50.57 - }
50.58 -}
50.59 -
50.60 -bool
50.61 -ke::EvaluateForConstant(Expression *expr, BoxedPrimitive *out)
50.62 -{
50.63 - switch (expr->kind()) {
50.64 - case AstNode::kBinaryExpression:
50.65 - {
50.66 - BoxedPrimitive left;
50.67 - BoxedPrimitive right;
50.68 - BinaryExpression *b = expr->toBinaryExpression();
50.69 - if (!EvaluateForConstant(b->left(), &left) ||
50.70 - !EvaluateForConstant(b->right(), &right))
50.71 - {
50.72 - return false;
50.73 - }
50.74 - return EvaluateBinaryOperation(b->token(), left, right, out);
50.75 - }
50.76 -
50.77 - case AstNode::kUnaryExpression:
50.78 - {
50.79 - BoxedPrimitive inner;
50.80 - UnaryExpression *u = expr->toUnaryExpression();
50.81 - if (!EvaluateForConstant(u->expression(), &inner))
50.82 - return false;
50.83 - return EvaluateUnaryOperation(u->token(), inner, out);
50.84 - }
50.85 -
50.86 - case AstNode::kBooleanLiteral:
50.87 - *out = BoxedPrimitive::Int(expr->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
50.88 - return true;
50.89 -
50.90 - case AstNode::kIntegerLiteral:
50.91 - *out = BoxedPrimitive::Int(expr->toIntegerLiteral()->value());
50.92 - return true;
50.93 -
50.94 - default:
50.95 - return false;
50.96 - }
50.97 -}
50.98 +/* vim: set ts=4 sw=4 tw=99 et:
50.99 + *
50.100 + * Copyright (C) 2012 David Anderson
50.101 + *
50.102 + * This file is part of SourcePawn.
50.103 + *
50.104 + * SourcePawn is free software: you can redistribute it and/or modify it under
50.105 + * the terms of the GNU General Public License as published by the Free
50.106 + * Software Foundation, either version 3 of the License, or (at your option)
50.107 + * any later version.
50.108 + *
50.109 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
50.110 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
50.111 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
50.112 + *
50.113 + * You should have received a copy of the GNU General Public License along with
50.114 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
50.115 + */
50.116 +#include "AST.h"
50.117 +#include "ConstantEvaluator.h"
50.118 +#include "../Heap-inl.h"
50.119 +#include "../Handles-inl.h"
50.120 +
50.121 +using namespace ke;
50.122 +
50.123 +static inline bool
50.124 +EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right,
50.125 + BoxedPrimitive *out)
50.126 +{
50.127 + switch (kind) {
50.128 + case TOK_PLUS:
50.129 + *out = BoxedPrimitive::Int(left.toInt() + right.toInt());
50.130 + return true;
50.131 +
50.132 + case TOK_SHL:
50.133 + *out = BoxedPrimitive::Int(left.toInt() << right.toInt());
50.134 + return true;
50.135 +
50.136 + default:
50.137 + return false;
50.138 + }
50.139 +}
50.140 +
50.141 +static inline bool
50.142 +EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out)
50.143 +{
50.144 + switch (kind) {
50.145 + case TOK_MINUS:
50.146 + *out = BoxedPrimitive::Int(-inner.toInt());
50.147 + return true;
50.148 +
50.149 + default:
50.150 + return false;
50.151 + }
50.152 +}
50.153 +
50.154 +bool
50.155 +ke::EvaluateForConstant(Expression *expr, BoxedPrimitive *out)
50.156 +{
50.157 + switch (expr->kind()) {
50.158 + case AstNode::kBinaryExpression:
50.159 + {
50.160 + BoxedPrimitive left;
50.161 + BoxedPrimitive right;
50.162 + BinaryExpression *b = expr->toBinaryExpression();
50.163 + if (!EvaluateForConstant(b->left(), &left) ||
50.164 + !EvaluateForConstant(b->right(), &right))
50.165 + {
50.166 + return false;
50.167 + }
50.168 + return EvaluateBinaryOperation(b->token(), left, right, out);
50.169 + }
50.170 +
50.171 + case AstNode::kUnaryExpression:
50.172 + {
50.173 + BoxedPrimitive inner;
50.174 + UnaryExpression *u = expr->toUnaryExpression();
50.175 + if (!EvaluateForConstant(u->expression(), &inner))
50.176 + return false;
50.177 + return EvaluateUnaryOperation(u->token(), inner, out);
50.178 + }
50.179 +
50.180 + case AstNode::kBooleanLiteral:
50.181 + *out = BoxedPrimitive::Int(expr->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0);
50.182 + return true;
50.183 +
50.184 + case AstNode::kIntegerLiteral:
50.185 + *out = BoxedPrimitive::Int(expr->toIntegerLiteral()->value());
50.186 + return true;
50.187 +
50.188 + default:
50.189 + return false;
50.190 + }
50.191 +}
51.1 --- a/src/compiler/ConstantEvaluator.h Mon Jun 10 00:46:29 2013 +0100
51.2 +++ b/src/compiler/ConstantEvaluator.h Mon Jun 10 01:04:43 2013 +0100
51.3 @@ -1,32 +1,32 @@
51.4 -/* vim: set ts=4 sw=4 tw=99 et:
51.5 - *
51.6 - * Copyright (C) 2012 David Anderson
51.7 - *
51.8 - * This file is part of SourcePawn.
51.9 - *
51.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
51.11 - * the terms of the GNU General Public License as published by the Free
51.12 - * Software Foundation, either version 3 of the License, or (at your option)
51.13 - * any later version.
51.14 - *
51.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
51.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
51.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
51.18 - *
51.19 - * You should have received a copy of the GNU General Public License along with
51.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
51.21 - */
51.22 -#ifndef _include_sp2_constant_evaluator_h_
51.23 -#define _include_sp2_constant_evaluator_h_
51.24 -
51.25 -#include "../Types.h"
51.26 -
51.27 -namespace ke {
51.28 -
51.29 -class Expression;
51.30 -
51.31 -bool EvaluateForConstant(Expression *expr, BoxedPrimitive *out);
51.32 -
51.33 -}
51.34 -
51.35 -#endif // _include_sp2_constant_evaluator_h_
51.36 +/* vim: set ts=4 sw=4 tw=99 et:
51.37 + *
51.38 + * Copyright (C) 2012 David Anderson
51.39 + *
51.40 + * This file is part of SourcePawn.
51.41 + *
51.42 + * SourcePawn is free software: you can redistribute it and/or modify it under
51.43 + * the terms of the GNU General Public License as published by the Free
51.44 + * Software Foundation, either version 3 of the License, or (at your option)
51.45 + * any later version.
51.46 + *
51.47 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
51.48 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
51.49 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
51.50 + *
51.51 + * You should have received a copy of the GNU General Public License along with
51.52 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
51.53 + */
51.54 +#ifndef _include_sp2_constant_evaluator_h_
51.55 +#define _include_sp2_constant_evaluator_h_
51.56 +
51.57 +#include "../Types.h"
51.58 +
51.59 +namespace ke {
51.60 +
51.61 +class Expression;
51.62 +
51.63 +bool EvaluateForConstant(Expression *expr, BoxedPrimitive *out);
51.64 +
51.65 +}
51.66 +
51.67 +#endif // _include_sp2_constant_evaluator_h_
52.1 --- a/src/compiler/HIR.cpp Mon Jun 10 00:46:29 2013 +0100
52.2 +++ b/src/compiler/HIR.cpp Mon Jun 10 01:04:43 2013 +0100
52.3 @@ -1,556 +1,556 @@
52.4 -/* vim: set ts=4 sw=4 tw=99 et:
52.5 - *
52.6 - * Copyright (C) 2012 David Anderson
52.7 - *
52.8 - * This file is part of JITCraft.
52.9 - *
52.10 - * JITCraft is free software: you can redistribute it and/or modify it under
52.11 - * the terms of the GNU General Public License as published by the Free
52.12 - * Software Foundation, either version 3 of the License, or (at your option)
52.13 - * any later version.
52.14 - *
52.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
52.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
52.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
52.18 - *
52.19 - * You should have received a copy of the GNU General Public License along with
52.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
52.21 - */
52.22 -#include "AST.h"
52.23 -#include "HIR.h"
52.24 -#include "BytecodeEmitter.h"
52.25 -#include "../Strings.h"
52.26 -#include "../Heap-inl.h"
52.27 -#include "../Handles-inl.h"
52.28 -
52.29 -using namespace ke;
52.30 -
52.31 -class HIRTranslator : public HIRVisitor
52.32 -{
52.33 - public:
52.34 - HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
52.35 - : zone_(zone),
52.36 - emitter_(emitter)
52.37 - {
52.38 - }
52.39 -
52.40 - void translate(HIR *hir) {
52.41 - hir->accept(this);
52.42 - }
52.43 -
52.44 - void visitBoolean(HBoolean *hir);
52.45 - void visitFloat(HFloat *hir);
52.46 - void visitInteger(HInteger *hir);
52.47 - void visitArray(HArray *hir);
52.48 - void visitCall(HCall *call);
52.49 - void visitStore(HStore *store);
52.50 - void visitUnary(HUnary *unary);
52.51 - void visitBinary(HBinary *binary);
52.52 - void visitLocal(HLocal *local);
52.53 - void visitGlobal(HGlobal *global);
52.54 - void visitConvert(HConvert *convert);
52.55 - void visitIndex(HIndex *index);
52.56 - void visitField(HField *field);
52.57 - void visitPostIncDec(HPostIncDec *hir);
52.58 - void visitToRef(HToRef *hir);
52.59 - void visitNewDependentArray(HNewDependentArray *hir);
52.60 - void visitImport(HImport *import);
52.61 -
52.62 - private:
52.63 - Zone *zone_;
52.64 - BytecodeEmitter &emitter_;
52.65 -};
52.66 -
52.67 -#define __ emitter_.
52.68 -
52.69 -void
52.70 -HIRTranslator::visitBoolean(HBoolean *hir)
52.71 -{
52.72 - if (hir->value())
52.73 - __ true_();
52.74 - else
52.75 - __ false_();
52.76 -}
52.77 -
52.78 -void
52.79 -HIRTranslator::visitFloat(HFloat *hir)
52.80 -{
52.81 - __ float_(hir->value());
52.82 -}
52.83 -
52.84 -void
52.85 -HIRTranslator::visitInteger(HInteger *hir)
52.86 -{
52.87 - __ int_(hir->value());
52.88 -}
52.89 -
52.90 -void
52.91 -HIRTranslator::visitArray(HArray *hir)
52.92 -{
52.93 - __ object(hir->array());
52.94 -
52.95 - if (hir->duplicate())
52.96 - __ duparray();
52.97 -}
52.98 -
52.99 -void
52.100 -HIRTranslator::visitCall(HCall *call)
52.101 -{
52.102 - Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
52.103 -
52.104 - assert(call->args()->length() == fun->parameters()->length());
52.105 -
52.106 - __ note_position(call->node()->pos());
52.107 -
52.108 - unsigned argc = call->args()->length();
52.109 - for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
52.110 - HIR *hir = call->args()->at(i);
52.111 - hir->accept(this);
52.112 - }
52.113 -
52.114 - call->callee()->accept(this);
52.115 - __ call(fun, argc);
52.116 -}
52.117 -
52.118 -void
52.119 -HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.120 -{
52.121 -}
52.122 -
52.123 -void
52.124 -HGlobal::hold(BytecodeEmitter &emitter_)
52.125 -{
52.126 -}
52.127 -
52.128 -void
52.129 -HGlobal::swapAndPick(BytecodeEmitter &emitter_)
52.130 -{
52.131 - __ dup();
52.132 -}
52.133 -
52.134 -void
52.135 -HGlobal::store(BytecodeEmitter &emitter_)
52.136 -{
52.137 - __ setglobal(sym_);
52.138 -}
52.139 -
52.140 -void
52.141 -HGlobal::load(BytecodeEmitter &emitter_)
52.142 -{
52.143 - __ getglobal(sym_);
52.144 -}
52.145 -
52.146 -bool
52.147 -HGlobal::ref(BytecodeEmitter &emitter_)
52.148 -{
52.149 - return false;
52.150 -}
52.151 -
52.152 -static inline Type *
52.153 -MaybeDereference(Type *type)
52.154 -{
52.155 - if (type->isReference())
52.156 - return ReferenceType::cast(type)->contained();
52.157 - return type;
52.158 -}
52.159 -
52.160 -HLocal::HLocal(AstNode *node, VariableSymbol *sym)
52.161 - : HLValue(node, MaybeDereference(sym->type())),
52.162 - sym_(sym)
52.163 -{
52.164 -}
52.165 -
52.166 -void
52.167 -HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.168 -{
52.169 - if (sym_->type()->isReference()) {
52.170 - if (sym_->storage() == VariableSymbol::Local)
52.171 - __ getlocal(sym_);
52.172 - else if (sym_->storage() == VariableSymbol::Arg)
52.173 - __ getarg(sym_);
52.174 - else
52.175 - assert(false);
52.176 - }
52.177 -}
52.178 -
52.179 -void
52.180 -HLocal::hold(BytecodeEmitter &emitter_)
52.181 -{
52.182 - if (sym_->type()->isReference())
52.183 - __ dup();
52.184 -}
52.185 -
52.186 -void
52.187 -HLocal::swapAndPick(BytecodeEmitter &emitter_)
52.188 -{
52.189 - if (sym_->type()->isReference()) {
52.190 - __ swap();
52.191 - __ pick2();
52.192 - } else {
52.193 - __ dup();
52.194 - }
52.195 -}
52.196 -
52.197 -void
52.198 -HLocal::store(BytecodeEmitter &emitter_)
52.199 -{
52.200 - if (sym_->type()->isReference()) {
52.201 - __ setref(ReferenceType::cast(sym_->type())->contained());
52.202 - } else {
52.203 - if (sym_->storage() == VariableSymbol::Local)
52.204 - __ setlocal(sym_);
52.205 - else if (sym_->storage() == VariableSymbol::Arg)
52.206 - __ setarg(sym_);
52.207 - else
52.208 - assert(false);
52.209 - }
52.210 -}
52.211 -
52.212 -void
52.213 -HLocal::load(BytecodeEmitter &emitter_)
52.214 -{
52.215 - if (sym_->type()->isReference())
52.216 - __ getref(ReferenceType::cast(sym_->type())->contained());
52.217 - else if (sym_->storage() == VariableSymbol::Local)
52.218 - __ getlocal(sym_);
52.219 - else if (sym_->storage() == VariableSymbol::Arg)
52.220 - __ getarg(sym_);
52.221 - else
52.222 - assert(false);
52.223 -}
52.224 -
52.225 -bool
52.226 -HLocal::ref(BytecodeEmitter &emitter_)
52.227 -{
52.228 - if (sym_->storage() == VariableSymbol::Heap) {
52.229 - // Closing over a reference should never pass SemA.
52.230 - assert(!sym_->type()->isReference());
52.231 -
52.232 - // We don't support direct references to heap-allocated locals. This
52.233 - // should probably be banned in SemA? But for now, just assert. :TODO:
52.234 - assert(false);
52.235 - return false;
52.236 - }
52.237 -
52.238 - if (sym_->type()->isReference()) {
52.239 - if (sym_->storage() == VariableSymbol::Local)
52.240 - __ getlocal(sym_);
52.241 - else if (sym_->storage() == VariableSymbol::Arg)
52.242 - __ getarg(sym_);
52.243 - else
52.244 - assert(false);
52.245 - } else {
52.246 - __ newref(sym_);
52.247 - }
52.248 -
52.249 - return true;
52.250 -}
52.251 -
52.252 -void
52.253 -HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.254 -{
52.255 - __ note_position(node()->pos());
52.256 - left_->accept(visitor);
52.257 - right_->accept(visitor);
52.258 -}
52.259 -
52.260 -void
52.261 -HIndex::hold(BytecodeEmitter &emitter_)
52.262 -{
52.263 - __ dup2();
52.264 -}
52.265 -
52.266 -void
52.267 -HIndex::swapAndPick(BytecodeEmitter &emitter_)
52.268 -{
52.269 - // BASE INDEX VALUE
52.270 - __ roll3(); // INDEX VALUE BASE
52.271 - __ roll3(); // VALUE BASE INDEX
52.272 - __ pick3(); // VALUE BASE INDEX VALUE
52.273 -}
52.274 -
52.275 -void
52.276 -HIndex::store(BytecodeEmitter &emitter_)
52.277 -{
52.278 - __ setelem(type());
52.279 -}
52.280 -
52.281 -void
52.282 -HIndex::load(BytecodeEmitter &emitter_)
52.283 -{
52.284 - __ getelem(type());
52.285 -}
52.286 -
52.287 -bool
52.288 -HIndex::ref(BytecodeEmitter &emitter_)
52.289 -{
52.290 - return false;
52.291 -}
52.292 -
52.293 -void
52.294 -HField::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.295 -{
52.296 - __ note_position(node()->pos());
52.297 - base_->accept(visitor);
52.298 -}
52.299 -
52.300 -void
52.301 -HField::hold(BytecodeEmitter &emitter_)
52.302 -{
52.303 - __ dup();
52.304 -}
52.305 -
52.306 -void
52.307 -HField::swapAndPick(BytecodeEmitter &emitter_)
52.308 -{
52.309 - // BASE VALUE
52.310 - __ swap(); // VALUE BASE
52.311 - __ pick2(); // VALUE BASE VALUE
52.312 -}
52.313 -
52.314 -void
52.315 -HField::store(BytecodeEmitter &emitter_)
52.316 -{
52.317 - __ setfield(index_, type());
52.318 -}
52.319 -
52.320 -void
52.321 -HField::load(BytecodeEmitter &emitter_)
52.322 -{
52.323 - __ getfield(index_, type());
52.324 -}
52.325 -
52.326 -bool
52.327 -HField::ref(BytecodeEmitter &emitter_)
52.328 -{
52.329 - return false;
52.330 -}
52.331 -
52.332 -void
52.333 -HIRTranslator::visitLocal(HLocal *local)
52.334 -{
52.335 - local->bind(this, emitter_);
52.336 - local->load(emitter_);
52.337 -}
52.338 -
52.339 -void
52.340 -HIRTranslator::visitIndex(HIndex *index)
52.341 -{
52.342 - index->bind(this, emitter_);
52.343 - index->load(emitter_);
52.344 -}
52.345 -
52.346 -void
52.347 -HIRTranslator::visitField(HField *field)
52.348 -{
52.349 - field->bind(this, emitter_);
52.350 - field->load(emitter_);
52.351 -}
52.352 -
52.353 -void
52.354 -HIRTranslator::visitGlobal(HGlobal *global)
52.355 -{
52.356 - global->bind(this, emitter_);
52.357 - global->load(emitter_);
52.358 -}
52.359 -
52.360 -static inline Opcode
52.361 -TokenToOpcode(TokenKind kind)
52.362 -{
52.363 - switch (kind) {
52.364 - case TOK_PLUS:
52.365 - case TOK_ASSIGN_ADD:
52.366 - case TOK_INCREMENT:
52.367 - return OP_ADD;
52.368 - case TOK_MINUS:
52.369 - case TOK_ASSIGN_SUB:
52.370 - case TOK_DECREMENT:
52.371 - return OP_SUB;
52.372 - case TOK_STAR:
52.373 - case TOK_ASSIGN_MUL:
52.374 - return OP_MUL;
52.375 - case TOK_SLASH:
52.376 - case TOK_ASSIGN_DIV:
52.377 - return OP_DIV;
52.378 - case TOK_PERCENT:
52.379 - case TOK_ASSIGN_MOD:
52.380 - return OP_MOD;
52.381 - case TOK_SHR:
52.382 - case TOK_ASSIGN_SHR:
52.383 - return OP_SHR;
52.384 - case TOK_USHR:
52.385 - case TOK_ASSIGN_USHR:
52.386 - return OP_USHR;
52.387 - case TOK_SHL:
52.388 - case TOK_ASSIGN_SHL:
52.389 - return OP_SHL;
52.390 - case TOK_BITAND:
52.391 - case TOK_ASSIGN_BITAND:
52.392 - return OP_BITAND;
52.393 - case TOK_BITOR:
52.394 - case TOK_ASSIGN_BITOR:
52.395 - return OP_BITOR;
52.396 - case TOK_GT:
52.397 - return OP_GT;
52.398 - case TOK_GE:
52.399 - return OP_GE;
52.400 - case TOK_LT:
52.401 - return OP_LT;
52.402 - case TOK_LE:
52.403 - return OP_LE;
52.404 - case TOK_EQUALS:
52.405 - return OP_EQ;
52.406 - case TOK_NOTEQUALS:
52.407 - return OP_NE;
52.408 - default:
52.409 - assert(kind == TOK_BITXOR);
52.410 - return OP_BITXOR;
52.411 - }
52.412 -}
52.413 -
52.414 -void
52.415 -HIRTranslator::visitStore(HStore *store)
52.416 -{
52.417 - store->lval()->bind(this, emitter_);
52.418 -
52.419 - if (store->kind() == TOK_ASSIGN) {
52.420 - // Fixed-length arrays and structs have copy semantics.
52.421 - Local<Type> type(zone_, store->lval()->type());
52.422 - if (type->isArray() && ArrayType::cast(type)->isFixedLength()) {
52.423 - store->lval()->load(emitter_);
52.424 - store->rval()->accept(this);
52.425 - __ copyarray();
52.426 - } else if (type->isStruct()) {
52.427 - store->lval()->load(emitter_);
52.428 - store->rval()->accept(this);
52.429 - __ copystruct();
52.430 - } else {
52.431 - store->rval()->accept(this);
52.432 - store->lval()->store(emitter_);
52.433 - }
52.434 - } else {
52.435 - // Advanced case: dup the ref, load, op, store.
52.436 - store->lval()->hold(emitter_);
52.437 - store->lval()->load(emitter_);
52.438 - store->rval()->accept(this);
52.439 - __ binary(TokenToOpcode(store->kind()));
52.440 - store->lval()->store(emitter_);
52.441 - }
52.442 -}
52.443 -
52.444 -void
52.445 -HIRTranslator::visitPostIncDec(HPostIncDec *hir)
52.446 -{
52.447 - hir->lval()->bind(this, emitter_);
52.448 - hir->lval()->hold(emitter_);
52.449 - hir->lval()->load(emitter_);
52.450 - hir->lval()->swapAndPick(emitter_);
52.451 - hir->rval()->accept(this);
52.452 - __ binary(TokenToOpcode(hir->kind()));
52.453 - hir->lval()->store(emitter_);
52.454 - __ pop();
52.455 -}
52.456 -
52.457 -void
52.458 -HIRTranslator::visitBinary(HBinary *binary)
52.459 -{
52.460 - binary->left()->accept(this);
52.461 - binary->right()->accept(this);
52.462 -
52.463 - // We define three sets of math operators:
52.464 - //
52.465 - // (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
52.466 - // the same type.
52.467 - // (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
52.468 - // a boolean.
52.469 - // (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
52.470 - // equal integer types and return that integer type.
52.471 - //
52.472 - Opcode op = TokenToOpcode(binary->token());
52.473 -
52.474 - if (op == OP_DIV)
52.475 - __ note_position(binary->node()->pos());
52.476 -
52.477 - if (op >= OP_ADD && op <= OP_NE) {
52.478 - if (binary->type()->isFloat())
52.479 - op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
52.480 - } else {
52.481 - assert(binary->type()->isInt32());
52.482 - }
52.483 -
52.484 - __ binary(op);
52.485 -}
52.486 -
52.487 -void
52.488 -HIRTranslator::visitUnary(HUnary *unary)
52.489 -{
52.490 - unary->in()->accept(this);
52.491 -
52.492 - switch (unary->token()) {
52.493 - case TOK_TILDE:
52.494 - __ bitnot();
52.495 - break;
52.496 -
52.497 - case TOK_MINUS:
52.498 - if (unary->type()->isFloat())
52.499 - __ neg_f();
52.500 - else
52.501 - __ neg();
52.502 - break;
52.503 -
52.504 - default:
52.505 - assert(unary->token() == TOK_LABEL);
52.506 - __ bitcast(unary->type());
52.507 - break;
52.508 - }
52.509 -}
52.510 -
52.511 -void
52.512 -HIRTranslator::visitConvert(HConvert *convert)
52.513 -{
52.514 - convert->in()->accept(this);
52.515 - __ unary(convert->opcode());
52.516 -}
52.517 -
52.518 -void
52.519 -HIRTranslator::visitToRef(HToRef *hir)
52.520 -{
52.521 - HIR *in = hir->in();
52.522 -
52.523 - // See if we can bind a direct reference.
52.524 - if (in->isLValue() && in->toLValue()->ref(emitter_))
52.525 - return;
52.526 -
52.527 - // No, we can't. So instead we create an on-stack reference.
52.528 - in->accept(this);
52.529 - __ slotref_lifo();
52.530 -}
52.531 -
52.532 -void
52.533 -HIRTranslator::visitNewDependentArray(HNewDependentArray *hir)
52.534 -{
52.535 - hir->base()->accept(this);
52.536 - hir->index()->accept(this);
52.537 -
52.538 - Local<ArrayType> type(zone_, ArrayType::cast(hir->type()));
52.539 -
52.540 - // The dependent map is used for the opcode, but is not attached.
52.541 - Local<ArrayMap> map(zone_, ArrayMap::NewDependent(zone_, type));
52.542 - if (!map)
52.543 - return;
52.544 -
52.545 - __ deparray(map);
52.546 -}
52.547 -
52.548 -void
52.549 -HIRTranslator::visitImport(HImport *import)
52.550 -{
52.551 - __ import(import->index());
52.552 -}
52.553 -
52.554 -void
52.555 -ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
52.556 -{
52.557 - HIRTranslator translator(zone, emitter);
52.558 - translator.translate(hir);
52.559 -}
52.560 +/* vim: set ts=4 sw=4 tw=99 et:
52.561 + *
52.562 + * Copyright (C) 2012 David Anderson
52.563 + *
52.564 + * This file is part of JITCraft.
52.565 + *
52.566 + * JITCraft is free software: you can redistribute it and/or modify it under
52.567 + * the terms of the GNU General Public License as published by the Free
52.568 + * Software Foundation, either version 3 of the License, or (at your option)
52.569 + * any later version.
52.570 + *
52.571 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
52.572 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
52.573 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
52.574 + *
52.575 + * You should have received a copy of the GNU General Public License along with
52.576 + * JITCraft. If not, see http://www.gnu.org/licenses/.
52.577 + */
52.578 +#include "AST.h"
52.579 +#include "HIR.h"
52.580 +#include "BytecodeEmitter.h"
52.581 +#include "../Strings.h"
52.582 +#include "../Heap-inl.h"
52.583 +#include "../Handles-inl.h"
52.584 +
52.585 +using namespace ke;
52.586 +
52.587 +class HIRTranslator : public HIRVisitor
52.588 +{
52.589 + public:
52.590 + HIRTranslator(Zone *zone, BytecodeEmitter &emitter)
52.591 + : zone_(zone),
52.592 + emitter_(emitter)
52.593 + {
52.594 + }
52.595 +
52.596 + void translate(HIR *hir) {
52.597 + hir->accept(this);
52.598 + }
52.599 +
52.600 + void visitBoolean(HBoolean *hir);
52.601 + void visitFloat(HFloat *hir);
52.602 + void visitInteger(HInteger *hir);
52.603 + void visitArray(HArray *hir);
52.604 + void visitCall(HCall *call);
52.605 + void visitStore(HStore *store);
52.606 + void visitUnary(HUnary *unary);
52.607 + void visitBinary(HBinary *binary);
52.608 + void visitLocal(HLocal *local);
52.609 + void visitGlobal(HGlobal *global);
52.610 + void visitConvert(HConvert *convert);
52.611 + void visitIndex(HIndex *index);
52.612 + void visitField(HField *field);
52.613 + void visitPostIncDec(HPostIncDec *hir);
52.614 + void visitToRef(HToRef *hir);
52.615 + void visitNewDependentArray(HNewDependentArray *hir);
52.616 + void visitImport(HImport *import);
52.617 +
52.618 + private:
52.619 + Zone *zone_;
52.620 + BytecodeEmitter &emitter_;
52.621 +};
52.622 +
52.623 +#define __ emitter_.
52.624 +
52.625 +void
52.626 +HIRTranslator::visitBoolean(HBoolean *hir)
52.627 +{
52.628 + if (hir->value())
52.629 + __ true_();
52.630 + else
52.631 + __ false_();
52.632 +}
52.633 +
52.634 +void
52.635 +HIRTranslator::visitFloat(HFloat *hir)
52.636 +{
52.637 + __ float_(hir->value());
52.638 +}
52.639 +
52.640 +void
52.641 +HIRTranslator::visitInteger(HInteger *hir)
52.642 +{
52.643 + __ int_(hir->value());
52.644 +}
52.645 +
52.646 +void
52.647 +HIRTranslator::visitArray(HArray *hir)
52.648 +{
52.649 + __ object(hir->array());
52.650 +
52.651 + if (hir->duplicate())
52.652 + __ duparray();
52.653 +}
52.654 +
52.655 +void
52.656 +HIRTranslator::visitCall(HCall *call)
52.657 +{
52.658 + Local<FunctionType> fun(zone_, FunctionType::cast(call->callee()->type()));
52.659 +
52.660 + assert(call->args()->length() == fun->parameters()->length());
52.661 +
52.662 + __ note_position(call->node()->pos());
52.663 +
52.664 + unsigned argc = call->args()->length();
52.665 + for (size_t i = call->args()->length() - 1; i < call->args()->length(); i--) {
52.666 + HIR *hir = call->args()->at(i);
52.667 + hir->accept(this);
52.668 + }
52.669 +
52.670 + call->callee()->accept(this);
52.671 + __ call(fun, argc);
52.672 +}
52.673 +
52.674 +void
52.675 +HGlobal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.676 +{
52.677 +}
52.678 +
52.679 +void
52.680 +HGlobal::hold(BytecodeEmitter &emitter_)
52.681 +{
52.682 +}
52.683 +
52.684 +void
52.685 +HGlobal::swapAndPick(BytecodeEmitter &emitter_)
52.686 +{
52.687 + __ dup();
52.688 +}
52.689 +
52.690 +void
52.691 +HGlobal::store(BytecodeEmitter &emitter_)
52.692 +{
52.693 + __ setglobal(sym_);
52.694 +}
52.695 +
52.696 +void
52.697 +HGlobal::load(BytecodeEmitter &emitter_)
52.698 +{
52.699 + __ getglobal(sym_);
52.700 +}
52.701 +
52.702 +bool
52.703 +HGlobal::ref(BytecodeEmitter &emitter_)
52.704 +{
52.705 + return false;
52.706 +}
52.707 +
52.708 +static inline Type *
52.709 +MaybeDereference(Type *type)
52.710 +{
52.711 + if (type->isReference())
52.712 + return ReferenceType::cast(type)->contained();
52.713 + return type;
52.714 +}
52.715 +
52.716 +HLocal::HLocal(AstNode *node, VariableSymbol *sym)
52.717 + : HLValue(node, MaybeDereference(sym->type())),
52.718 + sym_(sym)
52.719 +{
52.720 +}
52.721 +
52.722 +void
52.723 +HLocal::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.724 +{
52.725 + if (sym_->type()->isReference()) {
52.726 + if (sym_->storage() == VariableSymbol::Local)
52.727 + __ getlocal(sym_);
52.728 + else if (sym_->storage() == VariableSymbol::Arg)
52.729 + __ getarg(sym_);
52.730 + else
52.731 + assert(false);
52.732 + }
52.733 +}
52.734 +
52.735 +void
52.736 +HLocal::hold(BytecodeEmitter &emitter_)
52.737 +{
52.738 + if (sym_->type()->isReference())
52.739 + __ dup();
52.740 +}
52.741 +
52.742 +void
52.743 +HLocal::swapAndPick(BytecodeEmitter &emitter_)
52.744 +{
52.745 + if (sym_->type()->isReference()) {
52.746 + __ swap();
52.747 + __ pick2();
52.748 + } else {
52.749 + __ dup();
52.750 + }
52.751 +}
52.752 +
52.753 +void
52.754 +HLocal::store(BytecodeEmitter &emitter_)
52.755 +{
52.756 + if (sym_->type()->isReference()) {
52.757 + __ setref(ReferenceType::cast(sym_->type())->contained());
52.758 + } else {
52.759 + if (sym_->storage() == VariableSymbol::Local)
52.760 + __ setlocal(sym_);
52.761 + else if (sym_->storage() == VariableSymbol::Arg)
52.762 + __ setarg(sym_);
52.763 + else
52.764 + assert(false);
52.765 + }
52.766 +}
52.767 +
52.768 +void
52.769 +HLocal::load(BytecodeEmitter &emitter_)
52.770 +{
52.771 + if (sym_->type()->isReference())
52.772 + __ getref(ReferenceType::cast(sym_->type())->contained());
52.773 + else if (sym_->storage() == VariableSymbol::Local)
52.774 + __ getlocal(sym_);
52.775 + else if (sym_->storage() == VariableSymbol::Arg)
52.776 + __ getarg(sym_);
52.777 + else
52.778 + assert(false);
52.779 +}
52.780 +
52.781 +bool
52.782 +HLocal::ref(BytecodeEmitter &emitter_)
52.783 +{
52.784 + if (sym_->storage() == VariableSymbol::Heap) {
52.785 + // Closing over a reference should never pass SemA.
52.786 + assert(!sym_->type()->isReference());
52.787 +
52.788 + // We don't support direct references to heap-allocated locals. This
52.789 + // should probably be banned in SemA? But for now, just assert. :TODO:
52.790 + assert(false);
52.791 + return false;
52.792 + }
52.793 +
52.794 + if (sym_->type()->isReference()) {
52.795 + if (sym_->storage() == VariableSymbol::Local)
52.796 + __ getlocal(sym_);
52.797 + else if (sym_->storage() == VariableSymbol::Arg)
52.798 + __ getarg(sym_);
52.799 + else
52.800 + assert(false);
52.801 + } else {
52.802 + __ newref(sym_);
52.803 + }
52.804 +
52.805 + return true;
52.806 +}
52.807 +
52.808 +void
52.809 +HIndex::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.810 +{
52.811 + __ note_position(node()->pos());
52.812 + left_->accept(visitor);
52.813 + right_->accept(visitor);
52.814 +}
52.815 +
52.816 +void
52.817 +HIndex::hold(BytecodeEmitter &emitter_)
52.818 +{
52.819 + __ dup2();
52.820 +}
52.821 +
52.822 +void
52.823 +HIndex::swapAndPick(BytecodeEmitter &emitter_)
52.824 +{
52.825 + // BASE INDEX VALUE
52.826 + __ roll3(); // INDEX VALUE BASE
52.827 + __ roll3(); // VALUE BASE INDEX
52.828 + __ pick3(); // VALUE BASE INDEX VALUE
52.829 +}
52.830 +
52.831 +void
52.832 +HIndex::store(BytecodeEmitter &emitter_)
52.833 +{
52.834 + __ setelem(type());
52.835 +}
52.836 +
52.837 +void
52.838 +HIndex::load(BytecodeEmitter &emitter_)
52.839 +{
52.840 + __ getelem(type());
52.841 +}
52.842 +
52.843 +bool
52.844 +HIndex::ref(BytecodeEmitter &emitter_)
52.845 +{
52.846 + return false;
52.847 +}
52.848 +
52.849 +void
52.850 +HField::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_)
52.851 +{
52.852 + __ note_position(node()->pos());
52.853 + base_->accept(visitor);
52.854 +}
52.855 +
52.856 +void
52.857 +HField::hold(BytecodeEmitter &emitter_)
52.858 +{
52.859 + __ dup();
52.860 +}
52.861 +
52.862 +void
52.863 +HField::swapAndPick(BytecodeEmitter &emitter_)
52.864 +{
52.865 + // BASE VALUE
52.866 + __ swap(); // VALUE BASE
52.867 + __ pick2(); // VALUE BASE VALUE
52.868 +}
52.869 +
52.870 +void
52.871 +HField::store(BytecodeEmitter &emitter_)
52.872 +{
52.873 + __ setfield(index_, type());
52.874 +}
52.875 +
52.876 +void
52.877 +HField::load(BytecodeEmitter &emitter_)
52.878 +{
52.879 + __ getfield(index_, type());
52.880 +}
52.881 +
52.882 +bool
52.883 +HField::ref(BytecodeEmitter &emitter_)
52.884 +{
52.885 + return false;
52.886 +}
52.887 +
52.888 +void
52.889 +HIRTranslator::visitLocal(HLocal *local)
52.890 +{
52.891 + local->bind(this, emitter_);
52.892 + local->load(emitter_);
52.893 +}
52.894 +
52.895 +void
52.896 +HIRTranslator::visitIndex(HIndex *index)
52.897 +{
52.898 + index->bind(this, emitter_);
52.899 + index->load(emitter_);
52.900 +}
52.901 +
52.902 +void
52.903 +HIRTranslator::visitField(HField *field)
52.904 +{
52.905 + field->bind(this, emitter_);
52.906 + field->load(emitter_);
52.907 +}
52.908 +
52.909 +void
52.910 +HIRTranslator::visitGlobal(HGlobal *global)
52.911 +{
52.912 + global->bind(this, emitter_);
52.913 + global->load(emitter_);
52.914 +}
52.915 +
52.916 +static inline Opcode
52.917 +TokenToOpcode(TokenKind kind)
52.918 +{
52.919 + switch (kind) {
52.920 + case TOK_PLUS:
52.921 + case TOK_ASSIGN_ADD:
52.922 + case TOK_INCREMENT:
52.923 + return OP_ADD;
52.924 + case TOK_MINUS:
52.925 + case TOK_ASSIGN_SUB:
52.926 + case TOK_DECREMENT:
52.927 + return OP_SUB;
52.928 + case TOK_STAR:
52.929 + case TOK_ASSIGN_MUL:
52.930 + return OP_MUL;
52.931 + case TOK_SLASH:
52.932 + case TOK_ASSIGN_DIV:
52.933 + return OP_DIV;
52.934 + case TOK_PERCENT:
52.935 + case TOK_ASSIGN_MOD:
52.936 + return OP_MOD;
52.937 + case TOK_SHR:
52.938 + case TOK_ASSIGN_SHR:
52.939 + return OP_SHR;
52.940 + case TOK_USHR:
52.941 + case TOK_ASSIGN_USHR:
52.942 + return OP_USHR;
52.943 + case TOK_SHL:
52.944 + case TOK_ASSIGN_SHL:
52.945 + return OP_SHL;
52.946 + case TOK_BITAND:
52.947 + case TOK_ASSIGN_BITAND:
52.948 + return OP_BITAND;
52.949 + case TOK_BITOR:
52.950 + case TOK_ASSIGN_BITOR:
52.951 + return OP_BITOR;
52.952 + case TOK_GT:
52.953 + return OP_GT;
52.954 + case TOK_GE:
52.955 + return OP_GE;
52.956 + case TOK_LT:
52.957 + return OP_LT;
52.958 + case TOK_LE:
52.959 + return OP_LE;
52.960 + case TOK_EQUALS:
52.961 + return OP_EQ;
52.962 + case TOK_NOTEQUALS:
52.963 + return OP_NE;
52.964 + default:
52.965 + assert(kind == TOK_BITXOR);
52.966 + return OP_BITXOR;
52.967 + }
52.968 +}
52.969 +
52.970 +void
52.971 +HIRTranslator::visitStore(HStore *store)
52.972 +{
52.973 + store->lval()->bind(this, emitter_);
52.974 +
52.975 + if (store->kind() == TOK_ASSIGN) {
52.976 + // Fixed-length arrays and structs have copy semantics.
52.977 + Local<Type> type(zone_, store->lval()->type());
52.978 + if (type->isArray() && ArrayType::cast(type)->isFixedLength()) {
52.979 + store->lval()->load(emitter_);
52.980 + store->rval()->accept(this);
52.981 + __ copyarray();
52.982 + } else if (type->isStruct()) {
52.983 + store->lval()->load(emitter_);
52.984 + store->rval()->accept(this);
52.985 + __ copystruct();
52.986 + } else {
52.987 + store->rval()->accept(this);
52.988 + store->lval()->store(emitter_);
52.989 + }
52.990 + } else {
52.991 + // Advanced case: dup the ref, load, op, store.
52.992 + store->lval()->hold(emitter_);
52.993 + store->lval()->load(emitter_);
52.994 + store->rval()->accept(this);
52.995 + __ binary(TokenToOpcode(store->kind()));
52.996 + store->lval()->store(emitter_);
52.997 + }
52.998 +}
52.999 +
52.1000 +void
52.1001 +HIRTranslator::visitPostIncDec(HPostIncDec *hir)
52.1002 +{
52.1003 + hir->lval()->bind(this, emitter_);
52.1004 + hir->lval()->hold(emitter_);
52.1005 + hir->lval()->load(emitter_);
52.1006 + hir->lval()->swapAndPick(emitter_);
52.1007 + hir->rval()->accept(this);
52.1008 + __ binary(TokenToOpcode(hir->kind()));
52.1009 + hir->lval()->store(emitter_);
52.1010 + __ pop();
52.1011 +}
52.1012 +
52.1013 +void
52.1014 +HIRTranslator::visitBinary(HBinary *binary)
52.1015 +{
52.1016 + binary->left()->accept(this);
52.1017 + binary->right()->accept(this);
52.1018 +
52.1019 + // We define three sets of math operators:
52.1020 + //
52.1021 + // (1) ADD, SUB, MUL, DIV, MOD, which take two equal types and produce
52.1022 + // the same type.
52.1023 + // (2) LT, LE, GE, GT, EQ, NE, which take two equal types and produce
52.1024 + // a boolean.
52.1025 + // (3) SHL, SR, USHR, BITAND, BITOR, BITXOR, BITNOT, which take two
52.1026 + // equal integer types and return that integer type.
52.1027 + //
52.1028 + Opcode op = TokenToOpcode(binary->token());
52.1029 +
52.1030 + if (op == OP_DIV)
52.1031 + __ note_position(binary->node()->pos());
52.1032 +
52.1033 + if (op >= OP_ADD && op <= OP_NE) {
52.1034 + if (binary->type()->isFloat())
52.1035 + op = Opcode(int(op) + int(OP_ADD_F - OP_ADD));
52.1036 + } else {
52.1037 + assert(binary->type()->isInt32());
52.1038 + }
52.1039 +
52.1040 + __ binary(op);
52.1041 +}
52.1042 +
52.1043 +void
52.1044 +HIRTranslator::visitUnary(HUnary *unary)
52.1045 +{
52.1046 + unary->in()->accept(this);
52.1047 +
52.1048 + switch (unary->token()) {
52.1049 + case TOK_TILDE:
52.1050 + __ bitnot();
52.1051 + break;
52.1052 +
52.1053 + case TOK_MINUS:
52.1054 + if (unary->type()->isFloat())
52.1055 + __ neg_f();
52.1056 + else
52.1057 + __ neg();
52.1058 + break;
52.1059 +
52.1060 + default:
52.1061 + assert(unary->token() == TOK_LABEL);
52.1062 + __ bitcast(unary->type());
52.1063 + break;
52.1064 + }
52.1065 +}
52.1066 +
52.1067 +void
52.1068 +HIRTranslator::visitConvert(HConvert *convert)
52.1069 +{
52.1070 + convert->in()->accept(this);
52.1071 + __ unary(convert->opcode());
52.1072 +}
52.1073 +
52.1074 +void
52.1075 +HIRTranslator::visitToRef(HToRef *hir)
52.1076 +{
52.1077 + HIR *in = hir->in();
52.1078 +
52.1079 + // See if we can bind a direct reference.
52.1080 + if (in->isLValue() && in->toLValue()->ref(emitter_))
52.1081 + return;
52.1082 +
52.1083 + // No, we can't. So instead we create an on-stack reference.
52.1084 + in->accept(this);
52.1085 + __ slotref_lifo();
52.1086 +}
52.1087 +
52.1088 +void
52.1089 +HIRTranslator::visitNewDependentArray(HNewDependentArray *hir)
52.1090 +{
52.1091 + hir->base()->accept(this);
52.1092 + hir->index()->accept(this);
52.1093 +
52.1094 + Local<ArrayType> type(zone_, ArrayType::cast(hir->type()));
52.1095 +
52.1096 + // The dependent map is used for the opcode, but is not attached.
52.1097 + Local<ArrayMap> map(zone_, ArrayMap::NewDependent(zone_, type));
52.1098 + if (!map)
52.1099 + return;
52.1100 +
52.1101 + __ deparray(map);
52.1102 +}
52.1103 +
52.1104 +void
52.1105 +HIRTranslator::visitImport(HImport *import)
52.1106 +{
52.1107 + __ import(import->index());
52.1108 +}
52.1109 +
52.1110 +void
52.1111 +ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir)
52.1112 +{
52.1113 + HIRTranslator translator(zone, emitter);
52.1114 + translator.translate(hir);
52.1115 +}
53.1 --- a/src/compiler/HIR.h Mon Jun 10 00:46:29 2013 +0100
53.2 +++ b/src/compiler/HIR.h Mon Jun 10 01:04:43 2013 +0100
53.3 @@ -1,607 +1,607 @@
53.4 -/*
53.5 - * Copyright (C) 2012 David Anderson
53.6 - *
53.7 - * This file is part of SourcePawn.
53.8 - *
53.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
53.10 - * the terms of the GNU General Public License as published by the Free
53.11 - * Software Foundation, either version 3 of the License, or (at your option)
53.12 - * any later version.
53.13 - *
53.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
53.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
53.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
53.17 - *
53.18 - * You should have received a copy of the GNU General Public License along with
53.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
53.20 - */
53.21 -#ifndef _include_sp2_hir_h_
53.22 -#define _include_sp2_hir_h_
53.23 -
53.24 -#include "../Types.h"
53.25 -#include "../PoolAllocator.h"
53.26 -#include "../Opcodes.h"
53.27 -#include "Symbols.h"
53.28 -
53.29 -namespace ke {
53.30 -
53.31 -#define HIR_OPS(_) \
53.32 - _(Call) \
53.33 - _(Boolean) \
53.34 - _(Integer) \
53.35 - _(Float) \
53.36 - _(String) \
53.37 - _(Import) \
53.38 - _(Array) \
53.39 - _(Store) \
53.40 - _(ToRef) \
53.41 - _(NewDependentArray) \
53.42 - /* Special LValue types */ \
53.43 - _(Index) \
53.44 - _(Local) \
53.45 - _(Global) \
53.46 - _(Field) \
53.47 - /* End LValues */ \
53.48 - _(Unary) \
53.49 - _(Binary) \
53.50 - _(Convert) \
53.51 - _(PostIncDec)
53.52 -
53.53 -// Forward declarations.
53.54 -#define _(name) class H##name;
53.55 -HIR_OPS(_)
53.56 -#undef _
53.57 -
53.58 -class HIRVisitor;
53.59 -class AstNode;
53.60 -class HLValue;
53.61 -class Array;
53.62 -
53.63 -class HIR : public PoolObject
53.64 -{
53.65 - public:
53.66 - enum HOp {
53.67 -#define _(name) k##name,
53.68 - HIR_OPS(_)
53.69 -#undef _
53.70 - kTotalOps
53.71 - };
53.72 -
53.73 - public:
53.74 - HIR(AstNode *node, Type *type)
53.75 - : node_(node),
53.76 - type_(type)
53.77 - {
53.78 - }
53.79 -
53.80 - Handle<Type> type() {
53.81 - return type_;
53.82 - }
53.83 - AstNode *node() const {
53.84 - return node_;
53.85 - }
53.86 -
53.87 - virtual bool isLValue() const {
53.88 - return false;
53.89 - }
53.90 -
53.91 - virtual HOp op() const = 0;
53.92 - virtual void accept(HIRVisitor *visitor) = 0;
53.93 -
53.94 -#define _(name) \
53.95 - bool is##name() const { \
53.96 - return op() == k##name; \
53.97 - } \
53.98 - H##name *to##name() { \
53.99 - assert(is##name()); \
53.100 - return reinterpret_cast<H##name *>(this); \
53.101 - }
53.102 - HIR_OPS(_)
53.103 -#undef _
53.104 -
53.105 - HLValue *toLValue() {
53.106 - assert(isLValue());
53.107 - return reinterpret_cast<HLValue *>(this);
53.108 - }
53.109 -
53.110 - private:
53.111 - AstNode *node_;
53.112 - ScopedRoot<Type> type_;
53.113 -};
53.114 -
53.115 -class BytecodeEmitter;
53.116 -
53.117 -class HIRVisitor
53.118 -{
53.119 - public:
53.120 -#define _(name) \
53.121 - virtual void visit##name(H##name *hir) { \
53.122 - assert(false); \
53.123 - }
53.124 - HIR_OPS(_)
53.125 -#undef _
53.126 -};
53.127 -
53.128 -typedef PoolList<HIR *> HIRList;
53.129 -
53.130 -#define DEFINE_HIR(name) \
53.131 - virtual HOp op() const { \
53.132 - return k##name; \
53.133 - } \
53.134 - virtual void accept(HIRVisitor *visitor) { \
53.135 - visitor->visit##name(this); \
53.136 - }
53.137 -
53.138 -class HBoolean : public HIR
53.139 -{
53.140 - public:
53.141 - HBoolean(AstNode *node, Type *type, bool value)
53.142 - : HIR(node, type),
53.143 - value_(value)
53.144 - {
53.145 - }
53.146 -
53.147 - DEFINE_HIR(Boolean);
53.148 - bool value() const {
53.149 - return value_;
53.150 - }
53.151 -
53.152 - private:
53.153 - bool value_;
53.154 -};
53.155 -
53.156 -class HInteger : public HIR
53.157 -{
53.158 - public:
53.159 - HInteger(AstNode *node, Type *type, int value)
53.160 - : HIR(node, type),
53.161 - value_(value)
53.162 - {
53.163 - }
53.164 -
53.165 - DEFINE_HIR(Integer);
53.166 - int value() const {
53.167 - return value_;
53.168 - }
53.169 -
53.170 - private:
53.171 - int value_;
53.172 -};
53.173 -
53.174 -class HString : public HIR
53.175 -{
53.176 - public:
53.177 - HString(AstNode *node, Type *type, String *string)
53.178 - : HIR(node, type),
53.179 - string_(string)
53.180 - {
53.181 - }
53.182 -
53.183 - DEFINE_HIR(String);
53.184 - Handle<String> string() const {
53.185 - return string_;
53.186 - }
53.187 -
53.188 - private:
53.189 - ScopedRoot<String> string_;
53.190 -};
53.191 -
53.192 -class HImport : public HIR
53.193 -{
53.194 - public:
53.195 - HImport(AstNode *node, Type *type, unsigned index)
53.196 - : HIR(node, type),
53.197 - index_(index)
53.198 - {
53.199 - }
53.200 -
53.201 - DEFINE_HIR(Import);
53.202 - unsigned index() const {
53.203 - return index_;
53.204 - }
53.205 -
53.206 - private:
53.207 - unsigned index_;
53.208 -};
53.209 -
53.210 -class HArray : public HIR
53.211 -{
53.212 - public:
53.213 - HArray(AstNode *node, Type *type, Array *array, bool duplicate)
53.214 - : HIR(node, type),
53.215 - array_(array),
53.216 - duplicate_(duplicate)
53.217 - {
53.218 - }
53.219 -
53.220 - DEFINE_HIR(Array);
53.221 - Handle<Array> array() const {
53.222 - return array_;
53.223 - }
53.224 - bool duplicate() const {
53.225 - return duplicate_;
53.226 - }
53.227 -
53.228 - private:
53.229 - ScopedRoot<Array> array_;
53.230 - bool duplicate_;
53.231 -};
53.232 -
53.233 -class HConvert : public HIR
53.234 -{
53.235 - public:
53.236 - HConvert(AstNode *node, Type *type, Opcode op, HIR *in)
53.237 - : HIR(node, type),
53.238 - op_(op),
53.239 - in_(in)
53.240 - {
53.241 - }
53.242 -
53.243 - DEFINE_HIR(Convert);
53.244 - Opcode opcode() const {
53.245 - return op_;
53.246 - }
53.247 - HIR *in() const {
53.248 - return in_;
53.249 - }
53.250 -
53.251 - private:
53.252 - Opcode op_;
53.253 - HIR *in_;
53.254 -};
53.255 -
53.256 -class HLValue : public HIR
53.257 -{
53.258 - public:
53.259 - HLValue(AstNode *node, Type *type)
53.260 - : HIR(node, type)
53.261 - {
53.262 - }
53.263 -
53.264 - // Pushes a reference to the LValue on the stack.
53.265 - virtual void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) = 0;
53.266 -
53.267 - // Duplicates a stack reference.
53.268 - virtual void hold(BytecodeEmitter &emitter_) = 0;
53.269 -
53.270 - // Reorders the stack for a post-increment operation:
53.271 - // REF VAL -> VAL REF VAL
53.272 - virtual void swapAndPick(BytecodeEmitter &emitter_) = 0;
53.273 -
53.274 - // Given a stack layout of the form:
53.275 - // [-1] value
53.276 - // [-2..n] ref
53.277 - //
53.278 - // Emits a store to the reference.
53.279 - virtual void store(BytecodeEmitter &emitter_) = 0;
53.280 - virtual void load(BytecodeEmitter &emitter_) = 0;
53.281 -
53.282 - // Try to make a direct reference, if semantics allow it. False if the
53.283 - // caller must allocate a reference to the stack.
53.284 - virtual bool ref(BytecodeEmitter &emitter_) = 0;
53.285 -
53.286 - bool isLValue() const {
53.287 - return true;
53.288 - }
53.289 -};
53.290 -
53.291 -class HLocal : public HLValue
53.292 -{
53.293 - public:
53.294 - HLocal(AstNode *node, VariableSymbol *sym);
53.295 -
53.296 - DEFINE_HIR(Local);
53.297 -
53.298 - // Pushes a reference to the LValue on the stack.
53.299 - void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.300 - void hold(BytecodeEmitter &emitter_);
53.301 - void swapAndPick(BytecodeEmitter &emitter_);
53.302 - void store(BytecodeEmitter &emitter_);
53.303 - void load(BytecodeEmitter &emitter_);
53.304 - bool ref(BytecodeEmitter &emitter_);
53.305 -
53.306 - VariableSymbol *sym() const {
53.307 - return sym_;
53.308 - }
53.309 -
53.310 - private:
53.311 - VariableSymbol *sym_;
53.312 -};
53.313 -
53.314 -class HIndex : public HLValue
53.315 -{
53.316 - public:
53.317 - HIndex(AstNode *node, Type *type, HIR *left, HIR *right)
53.318 - : HLValue(node, type),
53.319 - left_(left),
53.320 - right_(right)
53.321 - {
53.322 - }
53.323 -
53.324 - DEFINE_HIR(Index);
53.325 -
53.326 - void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.327 - void hold(BytecodeEmitter &emitter_);
53.328 - void swapAndPick(BytecodeEmitter &emitter_);
53.329 - void store(BytecodeEmitter &emitter_);
53.330 - void load(BytecodeEmitter &emitter_);
53.331 - bool ref(BytecodeEmitter &emitter_);
53.332 -
53.333 - HIR *base() const {
53.334 - return left_;
53.335 - }
53.336 - HIR *index() const {
53.337 - return right_;
53.338 - }
53.339 -
53.340 - private:
53.341 - HIR *left_;
53.342 - HIR *right_;
53.343 -};
53.344 -
53.345 -class HField : public HLValue
53.346 -{
53.347 - public:
53.348 - HField(AstNode *node, HIR *left, Type *type, unsigned index)
53.349 - : HLValue(node, type),
53.350 - base_(left),
53.351 - index_(index)
53.352 - {
53.353 - }
53.354 -
53.355 - DEFINE_HIR(Field);
53.356 -
53.357 - void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.358 - void hold(BytecodeEmitter &emitter_);
53.359 - void swapAndPick(BytecodeEmitter &emitter_);
53.360 - void store(BytecodeEmitter &emitter_);
53.361 - void load(BytecodeEmitter &emitter_);
53.362 - bool ref(BytecodeEmitter &emitter_);
53.363 -
53.364 - HIR *base() const {
53.365 - return base_;
53.366 - }
53.367 - unsigned index() const {
53.368 - return index_;
53.369 - }
53.370 -
53.371 - private:
53.372 - HIR *base_;
53.373 - unsigned index_;
53.374 -};
53.375 -
53.376 -class HGlobal : public HLValue
53.377 -{
53.378 - public:
53.379 - HGlobal(AstNode *node, Symbol *sym)
53.380 - : HLValue(node, sym->type()),
53.381 - sym_(sym)
53.382 - {
53.383 - }
53.384 -
53.385 - DEFINE_HIR(Global);
53.386 -
53.387 - void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.388 - void hold(BytecodeEmitter &emitter_);
53.389 - void swapAndPick(BytecodeEmitter &emitter_);
53.390 - void store(BytecodeEmitter &emitter_);
53.391 - void load(BytecodeEmitter &emitter_);
53.392 - bool ref(BytecodeEmitter &emitter_);
53.393 -
53.394 - Symbol *sym() const {
53.395 - return sym_;
53.396 - }
53.397 -
53.398 - private:
53.399 - Symbol *sym_;
53.400 -};
53.401 -
53.402 -class HBinary : public HIR
53.403 -{
53.404 - public:
53.405 - HBinary(AstNode *node, Type *type, TokenKind token, HIR *left, HIR *right)
53.406 - : HIR(node, type),
53.407 - token_(token),
53.408 - left_(left),
53.409 - right_(right)
53.410 - {
53.411 - }
53.412 -
53.413 - DEFINE_HIR(Binary);
53.414 - TokenKind token() const {
53.415 - return token_;
53.416 - }
53.417 - HIR *left() const {
53.418 - return left_;
53.419 - }
53.420 - HIR *right() const {
53.421 - return right_;
53.422 - }
53.423 -
53.424 - private:
53.425 - TokenKind token_;
53.426 - HIR *left_;
53.427 - HIR *right_;
53.428 -};
53.429 -
53.430 -class HFloat : public HIR
53.431 -{
53.432 - public:
53.433 - HFloat(AstNode *node, Type *type, float value)
53.434 - : HIR(node, type),
53.435 - value_(value)
53.436 - {
53.437 - }
53.438 -
53.439 - DEFINE_HIR(Float);
53.440 - float value() const {
53.441 - return value_;
53.442 - }
53.443 -
53.444 - private:
53.445 - float value_;
53.446 -};
53.447 -
53.448 -class HUnary : public HIR
53.449 -{
53.450 - public:
53.451 - HUnary(AstNode *node, Type *type, TokenKind tok, HIR *in)
53.452 - : HIR(node, type),
53.453 - in_(in),
53.454 - token_(tok)
53.455 - {
53.456 - }
53.457 -
53.458 - DEFINE_HIR(Unary);
53.459 - HIR *in() const {
53.460 - return in_;
53.461 - }
53.462 - TokenKind token() const {
53.463 - return token_;
53.464 - }
53.465 -
53.466 - private:
53.467 - HIR *in_;
53.468 - TokenKind token_;
53.469 -};
53.470 -
53.471 -class HStore : public HIR
53.472 -{
53.473 - public:
53.474 - HStore(AstNode *node, HLValue *lval, HIR *rval)
53.475 - : HIR(node, lval->type()),
53.476 - kind_(TOK_ASSIGN),
53.477 - lval_(lval),
53.478 - rval_(rval)
53.479 - {
53.480 - }
53.481 -
53.482 - HStore(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
53.483 - : HIR(node, lval->type()),
53.484 - kind_(kind),
53.485 - lval_(lval),
53.486 - rval_(rval)
53.487 - {
53.488 - }
53.489 -
53.490 - DEFINE_HIR(Store);
53.491 -
53.492 - HLValue *lval() const {
53.493 - return lval_;
53.494 - }
53.495 - HIR *rval() const {
53.496 - return rval_;
53.497 - }
53.498 - TokenKind kind() const {
53.499 - return kind_;
53.500 - }
53.501 -
53.502 - private:
53.503 - TokenKind kind_;
53.504 - HLValue *lval_;
53.505 - HIR *rval_;
53.506 -};
53.507 -
53.508 -class HPostIncDec : public HIR
53.509 -{
53.510 - public:
53.511 - HPostIncDec(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
53.512 - : HIR(node, lval->type()),
53.513 - kind_(kind),
53.514 - lval_(lval),
53.515 - rval_(rval)
53.516 - {
53.517 - }
53.518 -
53.519 - DEFINE_HIR(PostIncDec);
53.520 -
53.521 - HLValue *lval() const {
53.522 - return lval_;
53.523 - }
53.524 - HIR *rval() const {
53.525 - return rval_;
53.526 - }
53.527 - TokenKind kind() const {
53.528 - return kind_;
53.529 - }
53.530 -
53.531 - private:
53.532 - TokenKind kind_;
53.533 - HLValue *lval_;
53.534 - HIR *rval_;
53.535 -};
53.536 -
53.537 -class HCall : public HIR
53.538 -{
53.539 - public:
53.540 - HCall(AstNode *node, Type *type, HIR *callee, HIRList *args)
53.541 - : HIR(node, type),
53.542 - callee_(callee),
53.543 - args_(args)
53.544 - {
53.545 - }
53.546 -
53.547 - DEFINE_HIR(Call);
53.548 -
53.549 - HIR *callee() const {
53.550 - return callee_;
53.551 - }
53.552 - HIRList *args() const {
53.553 - return args_;
53.554 - }
53.555 -
53.556 - private:
53.557 - HIR *callee_;
53.558 - HIRList *args_;
53.559 -};
53.560 -
53.561 -class HToRef : public HIR
53.562 -{
53.563 - public:
53.564 - HToRef(AstNode *node, Type *type, HIR *in)
53.565 - : HIR(node, type),
53.566 - in_(in)
53.567 - {
53.568 - }
53.569 -
53.570 - DEFINE_HIR(ToRef);
53.571 -
53.572 - HIR *in() const {
53.573 - return in_;
53.574 - }
53.575 -
53.576 - private:
53.577 - HIR *in_;
53.578 -};
53.579 -
53.580 -class HNewDependentArray : public HIR
53.581 -{
53.582 - public:
53.583 - HNewDependentArray(AstNode *node, Type *type, HIR *base, HIR *index)
53.584 - : HIR(node, type),
53.585 - base_(base),
53.586 - index_(index)
53.587 - {
53.588 - }
53.589 -
53.590 - DEFINE_HIR(NewDependentArray);
53.591 -
53.592 - HIR *base() const {
53.593 - return base_;
53.594 - }
53.595 - HIR *index() const {
53.596 - return index_;
53.597 - }
53.598 -
53.599 - private:
53.600 - HIR *base_;
53.601 - HIR *index_;
53.602 -};
53.603 -
53.604 -#undef DEFINE_HIR
53.605 -
53.606 -void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
53.607 -
53.608 -}
53.609 -
53.610 -#endif // _include_sp2_hir_h_
53.611 +/*
53.612 + * Copyright (C) 2012 David Anderson
53.613 + *
53.614 + * This file is part of SourcePawn.
53.615 + *
53.616 + * SourcePawn is free software: you can redistribute it and/or modify it under
53.617 + * the terms of the GNU General Public License as published by the Free
53.618 + * Software Foundation, either version 3 of the License, or (at your option)
53.619 + * any later version.
53.620 + *
53.621 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
53.622 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
53.623 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
53.624 + *
53.625 + * You should have received a copy of the GNU General Public License along with
53.626 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
53.627 + */
53.628 +#ifndef _include_sp2_hir_h_
53.629 +#define _include_sp2_hir_h_
53.630 +
53.631 +#include "../Types.h"
53.632 +#include "../PoolAllocator.h"
53.633 +#include "../Opcodes.h"
53.634 +#include "Symbols.h"
53.635 +
53.636 +namespace ke {
53.637 +
53.638 +#define HIR_OPS(_) \
53.639 + _(Call) \
53.640 + _(Boolean) \
53.641 + _(Integer) \
53.642 + _(Float) \
53.643 + _(String) \
53.644 + _(Import) \
53.645 + _(Array) \
53.646 + _(Store) \
53.647 + _(ToRef) \
53.648 + _(NewDependentArray) \
53.649 + /* Special LValue types */ \
53.650 + _(Index) \
53.651 + _(Local) \
53.652 + _(Global) \
53.653 + _(Field) \
53.654 + /* End LValues */ \
53.655 + _(Unary) \
53.656 + _(Binary) \
53.657 + _(Convert) \
53.658 + _(PostIncDec)
53.659 +
53.660 +// Forward declarations.
53.661 +#define _(name) class H##name;
53.662 +HIR_OPS(_)
53.663 +#undef _
53.664 +
53.665 +class HIRVisitor;
53.666 +class AstNode;
53.667 +class HLValue;
53.668 +class Array;
53.669 +
53.670 +class HIR : public PoolObject
53.671 +{
53.672 + public:
53.673 + enum HOp {
53.674 +#define _(name) k##name,
53.675 + HIR_OPS(_)
53.676 +#undef _
53.677 + kTotalOps
53.678 + };
53.679 +
53.680 + public:
53.681 + HIR(AstNode *node, Type *type)
53.682 + : node_(node),
53.683 + type_(type)
53.684 + {
53.685 + }
53.686 +
53.687 + Handle<Type> type() {
53.688 + return type_;
53.689 + }
53.690 + AstNode *node() const {
53.691 + return node_;
53.692 + }
53.693 +
53.694 + virtual bool isLValue() const {
53.695 + return false;
53.696 + }
53.697 +
53.698 + virtual HOp op() const = 0;
53.699 + virtual void accept(HIRVisitor *visitor) = 0;
53.700 +
53.701 +#define _(name) \
53.702 + bool is##name() const { \
53.703 + return op() == k##name; \
53.704 + } \
53.705 + H##name *to##name() { \
53.706 + assert(is##name()); \
53.707 + return reinterpret_cast<H##name *>(this); \
53.708 + }
53.709 + HIR_OPS(_)
53.710 +#undef _
53.711 +
53.712 + HLValue *toLValue() {
53.713 + assert(isLValue());
53.714 + return reinterpret_cast<HLValue *>(this);
53.715 + }
53.716 +
53.717 + private:
53.718 + AstNode *node_;
53.719 + ScopedRoot<Type> type_;
53.720 +};
53.721 +
53.722 +class BytecodeEmitter;
53.723 +
53.724 +class HIRVisitor
53.725 +{
53.726 + public:
53.727 +#define _(name) \
53.728 + virtual void visit##name(H##name *hir) { \
53.729 + assert(false); \
53.730 + }
53.731 + HIR_OPS(_)
53.732 +#undef _
53.733 +};
53.734 +
53.735 +typedef PoolList<HIR *> HIRList;
53.736 +
53.737 +#define DEFINE_HIR(name) \
53.738 + virtual HOp op() const { \
53.739 + return k##name; \
53.740 + } \
53.741 + virtual void accept(HIRVisitor *visitor) { \
53.742 + visitor->visit##name(this); \
53.743 + }
53.744 +
53.745 +class HBoolean : public HIR
53.746 +{
53.747 + public:
53.748 + HBoolean(AstNode *node, Type *type, bool value)
53.749 + : HIR(node, type),
53.750 + value_(value)
53.751 + {
53.752 + }
53.753 +
53.754 + DEFINE_HIR(Boolean);
53.755 + bool value() const {
53.756 + return value_;
53.757 + }
53.758 +
53.759 + private:
53.760 + bool value_;
53.761 +};
53.762 +
53.763 +class HInteger : public HIR
53.764 +{
53.765 + public:
53.766 + HInteger(AstNode *node, Type *type, int value)
53.767 + : HIR(node, type),
53.768 + value_(value)
53.769 + {
53.770 + }
53.771 +
53.772 + DEFINE_HIR(Integer);
53.773 + int value() const {
53.774 + return value_;
53.775 + }
53.776 +
53.777 + private:
53.778 + int value_;
53.779 +};
53.780 +
53.781 +class HString : public HIR
53.782 +{
53.783 + public:
53.784 + HString(AstNode *node, Type *type, String *string)
53.785 + : HIR(node, type),
53.786 + string_(string)
53.787 + {
53.788 + }
53.789 +
53.790 + DEFINE_HIR(String);
53.791 + Handle<String> string() const {
53.792 + return string_;
53.793 + }
53.794 +
53.795 + private:
53.796 + ScopedRoot<String> string_;
53.797 +};
53.798 +
53.799 +class HImport : public HIR
53.800 +{
53.801 + public:
53.802 + HImport(AstNode *node, Type *type, unsigned index)
53.803 + : HIR(node, type),
53.804 + index_(index)
53.805 + {
53.806 + }
53.807 +
53.808 + DEFINE_HIR(Import);
53.809 + unsigned index() const {
53.810 + return index_;
53.811 + }
53.812 +
53.813 + private:
53.814 + unsigned index_;
53.815 +};
53.816 +
53.817 +class HArray : public HIR
53.818 +{
53.819 + public:
53.820 + HArray(AstNode *node, Type *type, Array *array, bool duplicate)
53.821 + : HIR(node, type),
53.822 + array_(array),
53.823 + duplicate_(duplicate)
53.824 + {
53.825 + }
53.826 +
53.827 + DEFINE_HIR(Array);
53.828 + Handle<Array> array() const {
53.829 + return array_;
53.830 + }
53.831 + bool duplicate() const {
53.832 + return duplicate_;
53.833 + }
53.834 +
53.835 + private:
53.836 + ScopedRoot<Array> array_;
53.837 + bool duplicate_;
53.838 +};
53.839 +
53.840 +class HConvert : public HIR
53.841 +{
53.842 + public:
53.843 + HConvert(AstNode *node, Type *type, Opcode op, HIR *in)
53.844 + : HIR(node, type),
53.845 + op_(op),
53.846 + in_(in)
53.847 + {
53.848 + }
53.849 +
53.850 + DEFINE_HIR(Convert);
53.851 + Opcode opcode() const {
53.852 + return op_;
53.853 + }
53.854 + HIR *in() const {
53.855 + return in_;
53.856 + }
53.857 +
53.858 + private:
53.859 + Opcode op_;
53.860 + HIR *in_;
53.861 +};
53.862 +
53.863 +class HLValue : public HIR
53.864 +{
53.865 + public:
53.866 + HLValue(AstNode *node, Type *type)
53.867 + : HIR(node, type)
53.868 + {
53.869 + }
53.870 +
53.871 + // Pushes a reference to the LValue on the stack.
53.872 + virtual void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) = 0;
53.873 +
53.874 + // Duplicates a stack reference.
53.875 + virtual void hold(BytecodeEmitter &emitter_) = 0;
53.876 +
53.877 + // Reorders the stack for a post-increment operation:
53.878 + // REF VAL -> VAL REF VAL
53.879 + virtual void swapAndPick(BytecodeEmitter &emitter_) = 0;
53.880 +
53.881 + // Given a stack layout of the form:
53.882 + // [-1] value
53.883 + // [-2..n] ref
53.884 + //
53.885 + // Emits a store to the reference.
53.886 + virtual void store(BytecodeEmitter &emitter_) = 0;
53.887 + virtual void load(BytecodeEmitter &emitter_) = 0;
53.888 +
53.889 + // Try to make a direct reference, if semantics allow it. False if the
53.890 + // caller must allocate a reference to the stack.
53.891 + virtual bool ref(BytecodeEmitter &emitter_) = 0;
53.892 +
53.893 + bool isLValue() const {
53.894 + return true;
53.895 + }
53.896 +};
53.897 +
53.898 +class HLocal : public HLValue
53.899 +{
53.900 + public:
53.901 + HLocal(AstNode *node, VariableSymbol *sym);
53.902 +
53.903 + DEFINE_HIR(Local);
53.904 +
53.905 + // Pushes a reference to the LValue on the stack.
53.906 + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.907 + void hold(BytecodeEmitter &emitter_);
53.908 + void swapAndPick(BytecodeEmitter &emitter_);
53.909 + void store(BytecodeEmitter &emitter_);
53.910 + void load(BytecodeEmitter &emitter_);
53.911 + bool ref(BytecodeEmitter &emitter_);
53.912 +
53.913 + VariableSymbol *sym() const {
53.914 + return sym_;
53.915 + }
53.916 +
53.917 + private:
53.918 + VariableSymbol *sym_;
53.919 +};
53.920 +
53.921 +class HIndex : public HLValue
53.922 +{
53.923 + public:
53.924 + HIndex(AstNode *node, Type *type, HIR *left, HIR *right)
53.925 + : HLValue(node, type),
53.926 + left_(left),
53.927 + right_(right)
53.928 + {
53.929 + }
53.930 +
53.931 + DEFINE_HIR(Index);
53.932 +
53.933 + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.934 + void hold(BytecodeEmitter &emitter_);
53.935 + void swapAndPick(BytecodeEmitter &emitter_);
53.936 + void store(BytecodeEmitter &emitter_);
53.937 + void load(BytecodeEmitter &emitter_);
53.938 + bool ref(BytecodeEmitter &emitter_);
53.939 +
53.940 + HIR *base() const {
53.941 + return left_;
53.942 + }
53.943 + HIR *index() const {
53.944 + return right_;
53.945 + }
53.946 +
53.947 + private:
53.948 + HIR *left_;
53.949 + HIR *right_;
53.950 +};
53.951 +
53.952 +class HField : public HLValue
53.953 +{
53.954 + public:
53.955 + HField(AstNode *node, HIR *left, Type *type, unsigned index)
53.956 + : HLValue(node, type),
53.957 + base_(left),
53.958 + index_(index)
53.959 + {
53.960 + }
53.961 +
53.962 + DEFINE_HIR(Field);
53.963 +
53.964 + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.965 + void hold(BytecodeEmitter &emitter_);
53.966 + void swapAndPick(BytecodeEmitter &emitter_);
53.967 + void store(BytecodeEmitter &emitter_);
53.968 + void load(BytecodeEmitter &emitter_);
53.969 + bool ref(BytecodeEmitter &emitter_);
53.970 +
53.971 + HIR *base() const {
53.972 + return base_;
53.973 + }
53.974 + unsigned index() const {
53.975 + return index_;
53.976 + }
53.977 +
53.978 + private:
53.979 + HIR *base_;
53.980 + unsigned index_;
53.981 +};
53.982 +
53.983 +class HGlobal : public HLValue
53.984 +{
53.985 + public:
53.986 + HGlobal(AstNode *node, Symbol *sym)
53.987 + : HLValue(node, sym->type()),
53.988 + sym_(sym)
53.989 + {
53.990 + }
53.991 +
53.992 + DEFINE_HIR(Global);
53.993 +
53.994 + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_);
53.995 + void hold(BytecodeEmitter &emitter_);
53.996 + void swapAndPick(BytecodeEmitter &emitter_);
53.997 + void store(BytecodeEmitter &emitter_);
53.998 + void load(BytecodeEmitter &emitter_);
53.999 + bool ref(BytecodeEmitter &emitter_);
53.1000 +
53.1001 + Symbol *sym() const {
53.1002 + return sym_;
53.1003 + }
53.1004 +
53.1005 + private:
53.1006 + Symbol *sym_;
53.1007 +};
53.1008 +
53.1009 +class HBinary : public HIR
53.1010 +{
53.1011 + public:
53.1012 + HBinary(AstNode *node, Type *type, TokenKind token, HIR *left, HIR *right)
53.1013 + : HIR(node, type),
53.1014 + token_(token),
53.1015 + left_(left),
53.1016 + right_(right)
53.1017 + {
53.1018 + }
53.1019 +
53.1020 + DEFINE_HIR(Binary);
53.1021 + TokenKind token() const {
53.1022 + return token_;
53.1023 + }
53.1024 + HIR *left() const {
53.1025 + return left_;
53.1026 + }
53.1027 + HIR *right() const {
53.1028 + return right_;
53.1029 + }
53.1030 +
53.1031 + private:
53.1032 + TokenKind token_;
53.1033 + HIR *left_;
53.1034 + HIR *right_;
53.1035 +};
53.1036 +
53.1037 +class HFloat : public HIR
53.1038 +{
53.1039 + public:
53.1040 + HFloat(AstNode *node, Type *type, float value)
53.1041 + : HIR(node, type),
53.1042 + value_(value)
53.1043 + {
53.1044 + }
53.1045 +
53.1046 + DEFINE_HIR(Float);
53.1047 + float value() const {
53.1048 + return value_;
53.1049 + }
53.1050 +
53.1051 + private:
53.1052 + float value_;
53.1053 +};
53.1054 +
53.1055 +class HUnary : public HIR
53.1056 +{
53.1057 + public:
53.1058 + HUnary(AstNode *node, Type *type, TokenKind tok, HIR *in)
53.1059 + : HIR(node, type),
53.1060 + in_(in),
53.1061 + token_(tok)
53.1062 + {
53.1063 + }
53.1064 +
53.1065 + DEFINE_HIR(Unary);
53.1066 + HIR *in() const {
53.1067 + return in_;
53.1068 + }
53.1069 + TokenKind token() const {
53.1070 + return token_;
53.1071 + }
53.1072 +
53.1073 + private:
53.1074 + HIR *in_;
53.1075 + TokenKind token_;
53.1076 +};
53.1077 +
53.1078 +class HStore : public HIR
53.1079 +{
53.1080 + public:
53.1081 + HStore(AstNode *node, HLValue *lval, HIR *rval)
53.1082 + : HIR(node, lval->type()),
53.1083 + kind_(TOK_ASSIGN),
53.1084 + lval_(lval),
53.1085 + rval_(rval)
53.1086 + {
53.1087 + }
53.1088 +
53.1089 + HStore(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
53.1090 + : HIR(node, lval->type()),
53.1091 + kind_(kind),
53.1092 + lval_(lval),
53.1093 + rval_(rval)
53.1094 + {
53.1095 + }
53.1096 +
53.1097 + DEFINE_HIR(Store);
53.1098 +
53.1099 + HLValue *lval() const {
53.1100 + return lval_;
53.1101 + }
53.1102 + HIR *rval() const {
53.1103 + return rval_;
53.1104 + }
53.1105 + TokenKind kind() const {
53.1106 + return kind_;
53.1107 + }
53.1108 +
53.1109 + private:
53.1110 + TokenKind kind_;
53.1111 + HLValue *lval_;
53.1112 + HIR *rval_;
53.1113 +};
53.1114 +
53.1115 +class HPostIncDec : public HIR
53.1116 +{
53.1117 + public:
53.1118 + HPostIncDec(AstNode *node, TokenKind kind, HLValue *lval, HIR *rval)
53.1119 + : HIR(node, lval->type()),
53.1120 + kind_(kind),
53.1121 + lval_(lval),
53.1122 + rval_(rval)
53.1123 + {
53.1124 + }
53.1125 +
53.1126 + DEFINE_HIR(PostIncDec);
53.1127 +
53.1128 + HLValue *lval() const {
53.1129 + return lval_;
53.1130 + }
53.1131 + HIR *rval() const {
53.1132 + return rval_;
53.1133 + }
53.1134 + TokenKind kind() const {
53.1135 + return kind_;
53.1136 + }
53.1137 +
53.1138 + private:
53.1139 + TokenKind kind_;
53.1140 + HLValue *lval_;
53.1141 + HIR *rval_;
53.1142 +};
53.1143 +
53.1144 +class HCall : public HIR
53.1145 +{
53.1146 + public:
53.1147 + HCall(AstNode *node, Type *type, HIR *callee, HIRList *args)
53.1148 + : HIR(node, type),
53.1149 + callee_(callee),
53.1150 + args_(args)
53.1151 + {
53.1152 + }
53.1153 +
53.1154 + DEFINE_HIR(Call);
53.1155 +
53.1156 + HIR *callee() const {
53.1157 + return callee_;
53.1158 + }
53.1159 + HIRList *args() const {
53.1160 + return args_;
53.1161 + }
53.1162 +
53.1163 + private:
53.1164 + HIR *callee_;
53.1165 + HIRList *args_;
53.1166 +};
53.1167 +
53.1168 +class HToRef : public HIR
53.1169 +{
53.1170 + public:
53.1171 + HToRef(AstNode *node, Type *type, HIR *in)
53.1172 + : HIR(node, type),
53.1173 + in_(in)
53.1174 + {
53.1175 + }
53.1176 +
53.1177 + DEFINE_HIR(ToRef);
53.1178 +
53.1179 + HIR *in() const {
53.1180 + return in_;
53.1181 + }
53.1182 +
53.1183 + private:
53.1184 + HIR *in_;
53.1185 +};
53.1186 +
53.1187 +class HNewDependentArray : public HIR
53.1188 +{
53.1189 + public:
53.1190 + HNewDependentArray(AstNode *node, Type *type, HIR *base, HIR *index)
53.1191 + : HIR(node, type),
53.1192 + base_(base),
53.1193 + index_(index)
53.1194 + {
53.1195 + }
53.1196 +
53.1197 + DEFINE_HIR(NewDependentArray);
53.1198 +
53.1199 + HIR *base() const {
53.1200 + return base_;
53.1201 + }
53.1202 + HIR *index() const {
53.1203 + return index_;
53.1204 + }
53.1205 +
53.1206 + private:
53.1207 + HIR *base_;
53.1208 + HIR *index_;
53.1209 +};
53.1210 +
53.1211 +#undef DEFINE_HIR
53.1212 +
53.1213 +void EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir);
53.1214 +
53.1215 +}
53.1216 +
53.1217 +#endif // _include_sp2_hir_h_
54.1 --- a/src/compiler/NameBinding.cpp Mon Jun 10 00:46:29 2013 +0100
54.2 +++ b/src/compiler/NameBinding.cpp Mon Jun 10 01:04:43 2013 +0100
54.3 @@ -1,1297 +1,1297 @@
54.4 -/* vim: set ts=4 sw=4 tw=99 et:
54.5 - *
54.6 - * Copyright (C) 2012 David Anderson
54.7 - *
54.8 - * This file is part of SourcePawn.
54.9 - *
54.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
54.11 - * the terms of the GNU General Public License as published by the Free
54.12 - * Software Foundation, either version 3 of the License, or (at your option)
54.13 - * any later version.
54.14 - *
54.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
54.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
54.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
54.18 - *
54.19 - * You should have received a copy of the GNU General Public License along with
54.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
54.21 - */
54.22 -#include "../Strings.h"
54.23 -#include "../Zone.h"
54.24 -#include "../TypeManager.h"
54.25 -#include "NameBinding.h"
54.26 -#include "Scopes.h"
54.27 -#include "ConstantEvaluator.h"
54.28 -#include "../Spaces-inl.h"
54.29 -#include "../Heap-inl.h"
54.30 -
54.31 -using namespace ke;
54.32 -
54.33 -// Create symbol tables and symbols for every scope and declaration. For type
54.34 -// declarations and methods, we also pre-allocate a Type object, so that
54.35 -// circular dependencies between types will work.
54.36 -class NamePopulator : public AstVisitor
54.37 -{
54.38 - private:
54.39 - // This class is analagous to a Scope, however, it allows us to create
54.40 - // scopes lazily. If a scope is requested, and the current environment
54.41 - // has no scope, then a scope is created. If no scope is ever requested,
54.42 - // a scope does not need to be created.
54.43 - class SymbolEnv
54.44 - {
54.45 - public:
54.46 - SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL)
54.47 - : envp_(prevp),
54.48 - prev_(*prevp),
54.49 - scope_(scope)
54.50 - {
54.51 - *envp_ = this;
54.52 - }
54.53 - ~SymbolEnv() {
54.54 - *envp_ = prev_;
54.55 - }
54.56 -
54.57 - Scope *scope() {
54.58 - return scope_;
54.59 - }
54.60 - void setScope(Scope *scope) {
54.61 - assert(!scope_);
54.62 - scope_ = scope;
54.63 - }
54.64 - SymbolEnv *prev() const {
54.65 - return prev_;
54.66 - }
54.67 -
54.68 - private:
54.69 - SymbolEnv **envp_;
54.70 - SymbolEnv *prev_;
54.71 - Scope *scope_;
54.72 - };
54.73 -
54.74 - enum ReturnStatus {
54.75 - NoReturn,
54.76 - VoidReturn,
54.77 - ValueReturn
54.78 - };
54.79 -
54.80 - class FunctionScope
54.81 - {
54.82 - public:
54.83 - FunctionScope(FunctionScope **prevp)
54.84 - : prevp_(prevp),
54.85 - prev_(*prevp),
54.86 - status_(NoReturn)
54.87 - {
54.88 - *prevp_ = this;
54.89 - }
54.90 - ~FunctionScope() {
54.91 - *prevp_ = prev_;
54.92 - }
54.93 - ReturnStatus returns() const {
54.94 - return status_;
54.95 - }
54.96 - void returns(ReturnStatus status) {
54.97 - if (status > status_)
54.98 - status_ = status;
54.99 - }
54.100 - private:
54.101 - FunctionScope **prevp_;
54.102 - FunctionScope *prev_;
54.103 - ReturnStatus status_;
54.104 - };
54.105 -
54.106 - public:
54.107 - NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.108 - : zone_(zone),
54.109 - pool_(zone->pool()),
54.110 - cc_(cc),
54.111 - unit_(unit),
54.112 - env_(NULL),
54.113 - fun_(NULL)
54.114 - {
54.115 - }
54.116 -
54.117 - void analyze() {
54.118 - ImportScope *importScope = ImportScope::New(pool_);
54.119 - if (!importScope)
54.120 - return;
54.121 -
54.122 - // At the import level, we declare system types.
54.123 - if (!declareSystemTypes(importScope))
54.124 - return;
54.125 -
54.126 - GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
54.127 - if (!globalScope)
54.128 - return;
54.129 -
54.130 - unit_->setImportScope(importScope);
54.131 - unit_->setGlobalScope(globalScope);
54.132 -
54.133 - SymbolEnv env(&env_, globalScope);
54.134 -
54.135 - for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
54.136 - Statement *stmt = unit_->tree()->statements()->at(i);
54.137 - stmt->accept(this);
54.138 - }
54.139 -
54.140 - return;
54.141 - }
54.142 -
54.143 - bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> effective) {
54.144 - Local<String> tag(zone_, zone_->makeSymbol(name));
54.145 - if (!tag)
54.146 - return false;
54.147 -
54.148 - Local<Type> type(zone_, zone_->types()->getType());
54.149 -
54.150 - TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type, effective);
54.151 - return scope->addSymbol(sym);
54.152 - }
54.153 -
54.154 - bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) {
54.155 - Local<Type> primitive(zone_, zone_->types()->getPrimitive(prim));
54.156 - assert(primitive);
54.157 - return declareSystemType(scope, name, primitive);
54.158 - }
54.159 -
54.160 - bool declareSystemTypes(ImportScope *scope) {
54.161 - if (!declareSystemType(scope, "float", PrimitiveType_Float))
54.162 - return false;
54.163 - if (!declareSystemType(scope, "_", PrimitiveType_Int32))
54.164 - return false;
54.165 - if (!declareSystemType(scope, "int", PrimitiveType_Int32))
54.166 - return false;
54.167 - if (!declareSystemType(scope, "bool", PrimitiveType_Bool))
54.168 - return false;
54.169 - if (!declareSystemType(scope, "char", PrimitiveType_Char))
54.170 - return false;
54.171 -
54.172 - Local<Type> voidType(zone_, zone_->types()->getVoid());
54.173 - if (!declareSystemType(scope, "void", voidType))
54.174 - return false;
54.175 -
54.176 - return true;
54.177 - }
54.178 -
54.179 - void visitVariableDeclaration(VariableDeclaration *node) {
54.180 - Scope *scope = env_->scope();
54.181 - if (!scope || scope->kind() != Scope::GLOBAL) {
54.182 - if ((scope = getOrCreateBlockScope()) == NULL)
54.183 - return;
54.184 - }
54.185 -
54.186 - if (scope->kind() == Scope::GLOBAL) {
54.187 - // The symbol must be added now, since it could be an export.
54.188 - VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos());
54.189 - node->setSymbol(sym);
54.190 -
54.191 - if (!registerName(scope, sym))
54.192 - return;
54.193 - } else {
54.194 - // We ensure the scope will exist at the name binding phase, but
54.195 - // we don't actually register the variable symbol yet. Otherwise,
54.196 - // when binding the initializer, we could encounter:
54.197 - // new x = x;
54.198 - //
54.199 - // And we don't necessarily want this to bind.
54.200 - }
54.201 -
54.202 - if (node->initialization())
54.203 - node->initialization()->accept(this);
54.204 - }
54.205 -
54.206 - void visitEnumStatement(EnumStatement *node) {
54.207 - Local<String> name(zone_, node->name());
54.208 - Local<Type> type(zone_);
54.209 - if (name)
54.210 - type = zone_->types()->newEnum(name);
54.211 - else
54.212 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
54.213 -
54.214 - if (!type)
54.215 - return;
54.216 -
54.217 - Scope *scope = getGlobalOrCreateBlockScope();
54.218 - if (!scope)
54.219 - return;
54.220 -
54.221 - if (name) {
54.222 - Local<Type> symType(zone_, zone_->types()->getType());
54.223 - TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, symType, type);
54.224 - if (!registerName(scope, sym))
54.225 - return;
54.226 -
54.227 - if (scope->kind() == Scope::GLOBAL) {
54.228 - if (!unit_->globalScope()->exported()->append(sym))
54.229 - return;
54.230 - }
54.231 - }
54.232 -
54.233 - // We want each field of the expression to qualify as a constant expression.
54.234 - if ((type = zone_->types()->qualify(type, TypeQual_ConstExpr)) == NULL)
54.235 - return;
54.236 -
54.237 - int value = 0;
54.238 - for (size_t i = 0; i < node->entries()->length(); i++) {
54.239 - EnumStatement::Entry &entry = node->entries()->at(i);
54.240 - BoxedPrimitive box = BoxedPrimitive::Int(value);
54.241 - if (entry.expr) {
54.242 - if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
54.243 - cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
54.244 - return;
54.245 - }
54.246 -
54.247 - assert(box.type() == PrimitiveType_Int32);
54.248 - value = box.toInt();
54.249 - }
54.250 -
54.251 - ConstantSymbol *sym = new (pool_) ConstantSymbol(scope, entry.name, entry.pos, type, box);
54.252 - if (!registerName(scope, sym))
54.253 - return;
54.254 - if (scope->kind() == Scope::GLOBAL) {
54.255 - if (!unit_->globalScope()->exported()->append(sym))
54.256 - return;
54.257 - }
54.258 -
54.259 - entry.sym = sym;
54.260 - value++;
54.261 - }
54.262 - }
54.263 -
54.264 - void visitFunctionStatement(FunctionStatement *node) {
54.265 - // We create function types ahead of time, not for any particular
54.266 - // reason. It makes things consistent with FunctionTypeStatement,
54.267 - // which actually does produce a type.
54.268 - Local<FunctionType> type(zone_, FunctionType::New(zone_, node->name(), node->token()));
54.269 - if (!type)
54.270 - return;
54.271 -
54.272 - assert(env_->scope());
54.273 -
54.274 - // Function statements are always named, so add the name to the outer scope.
54.275 - FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type);
54.276 - if (!registerName(env_->scope(), sym))
54.277 - return;
54.278 -
54.279 - if (node->token() == TOK_PUBLIC ||
54.280 - node->token() == TOK_FORWARD ||
54.281 - node->token() == TOK_NATIVE)
54.282 - {
54.283 - // We're in the global scope, for sure.
54.284 - assert(env_->scope()->kind() == Scope::GLOBAL);
54.285 -
54.286 - if (!unit_->globalScope()->exported()->append(sym))
54.287 - return;
54.288 - }
54.289 -
54.290 - node->setSymbol(sym);
54.291 -
54.292 - // Scope for the function's arguments.
54.293 - SymbolEnv argEnv(&env_);
54.294 - if (!registerArguments(node->signature()))
54.295 - return;
54.296 -
54.297 - // Scope for function body.
54.298 - SymbolEnv localEnv(&env_);
54.299 - FunctionScope fun(&fun_);
54.300 - if (node->body())
54.301 - node->body()->accept(this);
54.302 -
54.303 - // Function statements have quirky semantics around their return
54.304 - // type. For reasonable compatibility with SP1, we use the following
54.305 - // heuristics for when no explicit type is declared.
54.306 - if (!node->signature().returnType()) {
54.307 - Local<Type> type(zone_);
54.308 - if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) {
54.309 - // If the function type is a native or forward, we always
54.310 - // assume it returns an int32.
54.311 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
54.312 - } else if (fun.returns() != ValueReturn) {
54.313 - // This function never returns a value, so mark it as
54.314 - // returning void.
54.315 - type = zone_->types()->getVoid();
54.316 - }
54.317 - // No need to NULL check here, we'll catch OOM later.
54.318 - node->sym()->type()->setReturnType(type);
54.319 - }
54.320 -
54.321 - node->setScopes(argEnv.scope(), localEnv.scope());
54.322 - }
54.323 -
54.324 - void visitStructureStatement(StructureStatement *node) {
54.325 - assert(false);
54.326 - }
54.327 -
54.328 - void visiFunctionTypeStatementt(FunctionTypeStatement *node) {
54.329 - assert(false);
54.330 - }
54.331 -
54.332 - void visitNameProxy(NameProxy *name) {
54.333 - }
54.334 - void visitAssignment(Assignment *node) {
54.335 - node->lvalue()->accept(this);
54.336 - node->expression()->accept(this);
54.337 - }
54.338 - void visitBinaryExpression(BinaryExpression *node) {
54.339 - node->left()->accept(this);
54.340 - node->right()->accept(this);
54.341 - }
54.342 - void visitReturnStatement(ReturnStatement *node) {
54.343 - if (node->expression())
54.344 - fun_->returns(ValueReturn);
54.345 - else
54.346 - fun_->returns(VoidReturn);
54.347 - }
54.348 - void visitForStatement(ForStatement *node) {
54.349 - SymbolEnv env(&env_);
54.350 -
54.351 - if (node->initialization())
54.352 - node->initialization()->accept(this);
54.353 - if (node->condition())
54.354 - node->condition()->accept(this);
54.355 - if (node->update())
54.356 - node->update()->accept(this);
54.357 - node->body()->accept(this);
54.358 -
54.359 - node->setScope(env.scope());
54.360 - }
54.361 - void visitBlockStatement(BlockStatement *node) {
54.362 - if (node->type() == TOK_NEW) {
54.363 - // Don't create a symbol environment for this block, since it
54.364 - // was created solely to house multiple variable decls.
54.365 - for (size_t i = 0; i < node->statements()->length(); i++)
54.366 - node->statements()->at(i)->accept(this);
54.367 - } else {
54.368 - assert(node->type() == TOK_LBRACE);
54.369 -
54.370 - SymbolEnv env(&env_);
54.371 -
54.372 - for (size_t i = 0; i < node->statements()->length(); i++)
54.373 - node->statements()->at(i)->accept(this);
54.374 -
54.375 - if (node->type() == TOK_NEW) {
54.376 - assert(!env.scope());
54.377 - return;
54.378 - }
54.379 -
54.380 - node->setScope(env.scope());
54.381 - }
54.382 - }
54.383 - void visitIntegerLiteral(IntegerLiteral *node) {
54.384 - }
54.385 - void visitExpressionStatement(ExpressionStatement *node) {
54.386 - node->expression()->accept(this);
54.387 - }
54.388 - void visitCallExpression(CallExpression *node) {
54.389 - node->callee()->accept(this);
54.390 - for (size_t i = 0; i < node->arguments()->length(); i++)
54.391 - node->arguments()->at(i)->accept(this);
54.392 - }
54.393 - void visitIfStatement(IfStatement *node) {
54.394 - node->ifTrue()->accept(this);
54.395 - if (node->ifFalse())
54.396 - node->ifFalse()->accept(this);
54.397 - }
54.398 - void visitIndexExpression(IndexExpression *node) {
54.399 - node->left()->accept(this);
54.400 - node->right()->accept(this);
54.401 - }
54.402 - void visitFloatLiteral(FloatLiteral *node) {
54.403 - }
54.404 - void visitWhileStatement(WhileStatement *node) {
54.405 - node->condition()->accept(this);
54.406 - node->body()->accept(this);
54.407 - }
54.408 - void visitBreakStatement(BreakStatement *node) {
54.409 - }
54.410 - void visitContinueStatement(ContinueStatement *node) {
54.411 - }
54.412 - void visitStringLiteral(StringLiteral *node) {
54.413 - }
54.414 - void visitIncDecExpression(IncDecExpression *node) {
54.415 - node->expression()->accept(this);
54.416 - }
54.417 - void visitUnaryExpression(UnaryExpression *node) {
54.418 - node->expression()->accept(this);
54.419 - }
54.420 - void visitTernaryExpression(TernaryExpression *node) {
54.421 - assert(false);
54.422 - }
54.423 - void visitBooleanLiteral(BooleanLiteral *node) {
54.424 - }
54.425 - void visitFieldExpression(FieldExpression *node) {
54.426 - }
54.427 - void visitSwitchStatement(SwitchStatement *node) {
54.428 - if (node->defaultCase())
54.429 - node->defaultCase()->accept(this);
54.430 -
54.431 - for (size_t i = 0; i < node->cases()->length(); i++)
54.432 - node->cases()->at(i)->statement()->accept(this);
54.433 - }
54.434 - void visitArrayLiteral(ArrayLiteral *node) {
54.435 - }
54.436 - void visitImportStatement(ImportStatement *node) {
54.437 - }
54.438 -
54.439 - private:
54.440 - Scope *getGlobalOrCreateBlockScope() {
54.441 - if (env_->scope()) {
54.442 - assert(env_->scope()->kind() == Scope::BLOCK ||
54.443 - env_->scope()->kind() == Scope::GLOBAL);
54.444 - return env_->scope();
54.445 - }
54.446 - return getOrCreateBlockScope();
54.447 - }
54.448 - Scope *getOrCreateBlockScope() {
54.449 - if (env_->scope()) {
54.450 - assert(env_->scope()->kind() == Scope::BLOCK);
54.451 - return env_->scope();
54.452 - }
54.453 -
54.454 - LocalScope *scope = LocalScope::New(pool_);
54.455 - if (!scope)
54.456 - return NULL;
54.457 -
54.458 - env_->setScope(scope);
54.459 - return scope;
54.460 - }
54.461 -
54.462 - bool registerName(Scope *scope, Symbol *sym) {
54.463 - if (!scope)
54.464 - return false;
54.465 -
54.466 - if (Symbol *other = scope->localLookup(sym->name())) {
54.467 - // Report, but allow errors to continue.
54.468 - cc_.reportError(sym->pos(), Message_RedeclaredName,
54.469 - sym->name()->chars(),
54.470 - other->pos().line,
54.471 - other->pos().col);
54.472 - return true;
54.473 - }
54.474 -
54.475 - return scope->addSymbol(sym);
54.476 - }
54.477 -
54.478 - bool registerArguments(const FunctionSignature &sig) {
54.479 - if (!sig.parameters()->length())
54.480 - return true;
54.481 -
54.482 - ArgumentScope *argScope = ArgumentScope::New(pool_);
54.483 - if (!argScope)
54.484 - return false;
54.485 - env_->setScope(argScope);
54.486 -
54.487 - for (size_t i = 0; i < sig.parameters()->length(); i++) {
54.488 - Parameter *param = sig.parameters()->at(i);
54.489 - VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos());
54.490 - if (!registerName(env_->scope(), sym))
54.491 - return false;
54.492 - param->setSymbol(sym);
54.493 - }
54.494 -
54.495 - return true;
54.496 - }
54.497 -
54.498 - private:
54.499 - Zone *zone_;
54.500 - PoolAllocator &pool_;
54.501 - CompileContext &cc_;
54.502 - TranslationUnit *unit_;
54.503 - SymbolEnv *env_;
54.504 - FunctionScope *fun_;
54.505 -};
54.506 -
54.507 -void
54.508 -ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.509 -{
54.510 - AutoEnterCompileContext enter(cc, unit);
54.511 - NamePopulator populator(zone, cc, unit);
54.512 - populator.analyze();
54.513 -}
54.514 -
54.515 -static const int INFER_ARRAY_SIZE = 0;
54.516 -static const int EVAL_ARRAY_SIZE = -1;
54.517 -static const int DYNAMIC_ARRAY_SIZE = -2;
54.518 -
54.519 -class NameBinderBase : public AstVisitor
54.520 -{
54.521 - public:
54.522 - NameBinderBase(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.523 - : zone_(zone),
54.524 - pool_(zone->pool()),
54.525 - cc_(cc),
54.526 - unit_(unit)
54.527 - {
54.528 - }
54.529 -
54.530 - protected:
54.531 - Type *buildVariableType(VariableDeclaration *node) {
54.532 - Local<Type> type(zone_, bindType(node->type(), node->quals()));
54.533 - if (!type)
54.534 - return NULL;
54.535 -
54.536 - // We don't allow array typedefs yet.
54.537 - assert(!type->isArray());
54.538 -
54.539 - if (node->dims()) {
54.540 - int dims[MAX_ARRAY_DEPTH];
54.541 - int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
54.542 - if (levels < 0)
54.543 - return NULL;
54.544 -
54.545 - // Do some extra inference based on the initializer, if present.
54.546 - Expression *init = node->initialization();
54.547 - if (init) {
54.548 - if (init->isArrayLiteral() && init->toArrayLiteral()->isFixed()) {
54.549 - Local<Type> contained(zone_, type->isArray()
54.550 - ? ArrayType::cast(type)->contained()
54.551 - : type);
54.552 - if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels))
54.553 - return NULL;
54.554 - } else if (init->isStringLiteral()) {
54.555 - dims[levels - 1] = init->toStringLiteral()->string()->length() + 1;
54.556 - }
54.557 - }
54.558 -
54.559 - // If we got extra dimensions, we need to build a new type.
54.560 - if (node->dims()) {
54.561 - if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL)
54.562 - return NULL;
54.563 - }
54.564 - }
54.565 -
54.566 - return type;
54.567 - }
54.568 -
54.569 - int evaluateDimensions(const SourcePosition &pos, Handle<Type> typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) {
54.570 - unsigned level = 0;
54.571 - Local<Type> type(zone_, typeArg);
54.572 - while (type->isArray()) {
54.573 - ArrayType *atype = ArrayType::cast(type);
54.574 - dims[level] = atype->isFixedLength()
54.575 - ? atype->fixedLength()
54.576 - : DYNAMIC_ARRAY_SIZE;
54.577 - type = atype->contained();
54.578 - level++;
54.579 - }
54.580 -
54.581 - if (!exprs)
54.582 - return level;
54.583 -
54.584 - if (level + exprs->length() > MAX_ARRAY_DEPTH) {
54.585 - cc_.reportError(pos, Message_MaximumArrayDepth);
54.586 - return -1;
54.587 - }
54.588 -
54.589 - bool hadEmptySize = false;
54.590 - for (size_t i = 0; i < exprs->length(); i++) {
54.591 - Expression *expr = exprs->at(i);
54.592 - if (!expr) {
54.593 - dims[i] = INFER_ARRAY_SIZE;
54.594 - hadEmptySize = true;
54.595 - continue;
54.596 - }
54.597 -
54.598 - BoxedPrimitive box;
54.599 - if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
54.600 - int size = box.toInt();
54.601 - if (size <= 0) {
54.602 - cc_.reportError(expr->pos(), Message_BadArraySize);
54.603 - return false;
54.604 - }
54.605 -
54.606 - dims[i] = size;
54.607 - continue;
54.608 - }
54.609 -
54.610 - if (hadEmptySize) {
54.611 - cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
54.612 - return false;
54.613 - }
54.614 -
54.615 - dims[i] = EVAL_ARRAY_SIZE;
54.616 - }
54.617 -
54.618 - return level + exprs->length();
54.619 - }
54.620 -
54.621 - // This function computes missing dimension sizes based on a literal
54.622 - // initializer. We don't really handle any size rules here; we just
54.623 - // do a really dumb inference.
54.624 - bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], int levels) {
54.625 - for (int i = 0; i < levels; i++) {
54.626 - if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) {
54.627 - // The following are invalid:
54.628 - // new x[<expr>] = {...}
54.629 - // new Type:x = {...} // where Type is a non-fixed array type
54.630 - cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray);
54.631 - return false;
54.632 - }
54.633 -
54.634 - if (dims[i] == INFER_ARRAY_SIZE) {
54.635 - // Character arrays are always dynamic when inferred from string literals.
54.636 - if (i == levels - 1 && contained->isChar())
54.637 - dims[i] = DYNAMIC_ARRAY_SIZE;
54.638 - else
54.639 - dims[i] = lit->expressions()->length();
54.640 - }
54.641 -
54.642 - if (i != levels - 1) {
54.643 - // Fixed array literals are guaranteed to have at least one expression.
54.644 - Expression *next = lit->expressions()->at(0);
54.645 - if (!next->isArrayLiteral()) {
54.646 - // Whelp... this array is just malformed. Not the best error message
54.647 - // but whatever.
54.648 - cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined);
54.649 - return false;
54.650 - }
54.651 - lit = next->toArrayLiteral();
54.652 - }
54.653 - }
54.654 -
54.655 - return true;
54.656 - }
54.657 -
54.658 - ArrayType *buildArrayType(Handle<Type> contained, TypeQualifiers quals, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
54.659 - Local<Type> type(zone_, contained);
54.660 -
54.661 - for (size_t i = postlevels - 1; i < postlevels; i--) {
54.662 - int size = dims[i] > 0
54.663 - ? dims[i]
54.664 - : ArrayType::DYNAMIC_ARRAY_SIZE;
54.665 -
54.666 - if ((type = zone_->types()->newArray(contained, size)) == NULL)
54.667 - return NULL;
54.668 - if ((type = zone_->types()->qualify(type, quals)) == NULL)
54.669 - return NULL;
54.670 - }
54.671 - return ArrayType::cast(type);
54.672 - }
54.673 -
54.674 - bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
54.675 - Local<Type> type(zone_);
54.676 - if (!fun->returnType()) {
54.677 - if ((type = bindType(sig.returnType(), TypeQual_None)) == NULL)
54.678 - return false;
54.679 - fun->setReturnType(type);
54.680 - }
54.681 -
54.682 - if (sig.variadic())
54.683 - fun->setVariadic();
54.684 -
54.685 - Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
54.686 - if (!params)
54.687 - return false;
54.688 -
54.689 - for (size_t i = 0; i < sig.parameters()->length(); i++) {
54.690 - Parameter *param = sig.parameters()->at(i);
54.691 - if ((type = bindType(param->type(), param->quals())) == NULL)
54.692 - return false;
54.693 -
54.694 - assert(!type->isArray());
54.695 -
54.696 - if (param->dims()) {
54.697 - int dims[MAX_ARRAY_DEPTH];
54.698 - int levels = evaluateDimensions(param->pos(), type, param->dims(), dims);
54.699 - if (levels < 0)
54.700 - return false;
54.701 -
54.702 - // If we got extra dimensions, we need to build a new type.
54.703 - // Unlike variables, we do not infer anything about array
54.704 - // sizes from its default initializer.
54.705 - if (param->dims()) {
54.706 - if ((type = buildArrayType(type, param->quals(), dims, param->dims()->length())) == NULL)
54.707 - return false;
54.708 - }
54.709 -
54.710 - if (ArrayType::cast(type)->innermost()->isVoid()) {
54.711 - cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
54.712 - return false;
54.713 - }
54.714 - }
54.715 -
54.716 - if (param->reference()) {
54.717 - if (!type->isPod()) {
54.718 - cc_.reportError(param->pos(), Message_ArrayCantBeReference);
54.719 - return false;
54.720 - }
54.721 - if (param->quals() & TypeQual_Const) {
54.722 - cc_.reportError(param->pos(), Message_CannotConstReference);
54.723 - return false;
54.724 - }
54.725 - if ((type = zone_->types()->getReference(type, false)) == NULL)
54.726 - return false;
54.727 - }
54.728 - if (param->quals() & TypeQual_Const) {
54.729 - if (!type->isArray() && !type->isStruct()) {
54.730 - cc_.reportError(param->pos(), Message_InvalidConstOnFormal);
54.731 - return false;
54.732 - }
54.733 - }
54.734 -
54.735 - if (type->isVoid()) {
54.736 - cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
54.737 - return false;
54.738 - }
54.739 -
54.740 - params->set(zone_, i, type);
54.741 - param->sym()->setType(type);
54.742 - }
54.743 -
54.744 - fun->setParameterTypes(params);
54.745 -
54.746 - return true;
54.747 - }
54.748 -
54.749 - Type *bindType(Expression *expr, TypeQualifiers quals) {
54.750 - Local<Type> type(zone_);
54.751 -
54.752 - if (!expr) {
54.753 - // If no type was declared, we return int32.
54.754 - type = zone_->types()->getPrimitive(PrimitiveType_Int32);
54.755 - } else {
54.756 - expr->accept(this);
54.757 -
54.758 - NameProxy *proxy = expr->asNameProxy();
54.759 - assert(proxy);
54.760 -
54.761 - Symbol *sym = proxy->sym();
54.762 - if (!sym)
54.763 - return NULL;
54.764 -
54.765 - if (!sym->isType()) {
54.766 - cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
54.767 - return NULL;
54.768 - }
54.769 -
54.770 - type = sym->toType()->effective();
54.771 - }
54.772 -
54.773 - return zone_->types()->qualify(type, quals);
54.774 - }
54.775 -
54.776 - protected:
54.777 - Zone *zone_;
54.778 - PoolAllocator &pool_;
54.779 - CompileContext &cc_;
54.780 - TranslationUnit *unit_;
54.781 -};
54.782 -
54.783 -class GlobalBuilder : public NameBinderBase
54.784 -{
54.785 - typedef ScopedRoot<Descriptor> ScopedDescriptor;
54.786 - struct PrimitiveFill {
54.787 - ScopedDescriptor *desc;
54.788 - BoxedPrimitive prim;
54.789 -
54.790 - PrimitiveFill(ScopedDescriptor *desc, BoxedPrimitive prim)
54.791 - : desc(desc),
54.792 - prim(prim)
54.793 - {
54.794 - }
54.795 - };
54.796 -
54.797 - public:
54.798 - GlobalBuilder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.799 - : NameBinderBase(zone, cc, unit),
54.800 - globalScope_(unit->globalScope())
54.801 - {
54.802 - }
54.803 -
54.804 - Struct *build() {
54.805 - for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
54.806 - unit_->tree()->imports()->at(i)->accept(this);
54.807 -
54.808 - // Next, enter the global scope and walk all statements.
54.809 - for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
54.810 - Statement *stmt = unit_->tree()->statements()->at(i);
54.811 - stmt->accept(this);
54.812 - }
54.813 -
54.814 - Local<Struct> globals(zone_, createGlobals());
54.815 - if (!globals)
54.816 - return NULL;
54.817 -
54.818 - populate(globals);
54.819 -
54.820 - return globals;
54.821 - }
54.822 -
54.823 - private:
54.824 - Struct *createGlobals() {
54.825 - Local<FixedArray> descs(zone_, FixedArray::New(zone_, descriptors_.length(), Heap::Tenure_Old));
54.826 - if (!descs)
54.827 - return NULL;
54.828 -
54.829 - for (unsigned i = 0; i < descriptors_.length(); i++)
54.830 - descs->set(zone_, i, *descriptors_[i]);
54.831 -
54.832 - Local<String> name(zone_, unit_->module()->name());
54.833 - Local<StructType> type(zone_, StructType::New(zone_, name, descs));
54.834 - if (!type)
54.835 - return NULL;
54.836 -
54.837 - Local<StructMap> map(zone_, type->newMap());
54.838 - return Struct::New(zone_, map, Heap::Tenure_Old);
54.839 - }
54.840 -
54.841 - void populate(Handle<Struct> globals) {
54.842 - // This is a huge hack, but it's probably better than a full extra
54.843 - // pass. The problem is that until we have all the descriptors, we
54.844 - // can't start setting constexprs in the struct, and we need to set
54.845 - // them now so they're available during full semantic analysis. To
54.846 - // work around this, we build up the list of values we need to set
54.847 - // as we build up descriptors, and then populate the global struct
54.848 - // with this set.
54.849 - //
54.850 - // Note, this code is also kind of dead until we support linking. We
54.851 - // handle constexprs explicitly in importFrom(), by sniffing out the
54.852 - // symbol type. That code will go away later.
54.853 - for (size_t i = 0; i < primitiveFills_.length(); i++) {
54.854 - const PrimitiveFill &fill = primitiveFills_[i];
54.855 - assert(fill.prim.type() == PrimitiveType_Int32);
54.856 - globals->set(*fill.desc, fill.prim.toInt());
54.857 - }
54.858 - }
54.859 -
54.860 - public:
54.861 - void visitEnumStatement(EnumStatement *stmt) {
54.862 - if (stmt->visibility() != TOK_PUBLIC || !stmt->name())
54.863 - return;
54.864 -
54.865 - Local<Type> type(zone_, zone_->types()->getType());
54.866 - Descriptor *desc = Descriptor::New(zone_, stmt->name(), type, Descriptor::Public);
54.867 - if (!desc)
54.868 - return;
54.869 - if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
54.870 - return;
54.871 -
54.872 - for (size_t i = 0; i < stmt->entries()->length(); i++) {
54.873 - EnumStatement::Entry &e = stmt->entries()->at(i);
54.874 - ScopedDescriptor *desc = new (pool_) ScopedDescriptor(Descriptor::New(zone_, e.name, e.sym->type(), Descriptor::Public));
54.875 - if (!desc || !descriptors_.append(desc))
54.876 - return;
54.877 -
54.878 - // Save the value so we can export it immediately.
54.879 - if (!primitiveFills_.append(PrimitiveFill(desc, e.sym->value())))
54.880 - return;
54.881 - }
54.882 - }
54.883 -
54.884 - void visitNameProxy(NameProxy *proxy) {
54.885 - Scope *scope = unit_->globalScope();
54.886 - Symbol *sym = scope->lookup(proxy->name());
54.887 - if (!sym)
54.888 - cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
54.889 - proxy->bind(sym);
54.890 - }
54.891 -
54.892 - void visitFunctionStatement(FunctionStatement *node) {
54.893 - Local<FunctionType> type(zone_, node->sym()->type());
54.894 - if (!fillFunctionType(type, node->signature()))
54.895 - return;
54.896 -
54.897 - unsigned offset;
54.898 - if (!builder_.add(type, &offset))
54.899 - return;
54.900 -
54.901 - Descriptor::Visibility visibility = (node->token() == TOK_NATIVE || node->token() == TOK_FORWARD)
54.902 - ? Descriptor::Public
54.903 - : Descriptor::Private;
54.904 -
54.905 - Descriptor *desc = Descriptor::New(zone_, node->name(), type, visibility);
54.906 - if (!desc)
54.907 - return;
54.908 - if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
54.909 - return;
54.910 - }
54.911 -
54.912 - void visitVariableDeclaration(VariableDeclaration *node) {
54.913 - Local<Type> type(zone_, buildVariableType(node));
54.914 - if (!type)
54.915 - return;
54.916 -
54.917 - // If we're in global scope, and we received a |const| qualifier, then
54.918 - // we extend this to array references as well. This is to sort of mimic
54.919 - // SP1 functionality, but also means that you cannot have changeable
54.920 - // const pointers in global scope.
54.921 - if ((node->quals() & TypeQual_Const) && type->isArray()) {
54.922 - if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL)
54.923 - return;
54.924 - }
54.925 -
54.926 - node->sym()->setType(type);
54.927 -
54.928 - unsigned offset;
54.929 - if (!builder_.add(type, &offset))
54.930 - return;
54.931 -
54.932 - Descriptor *desc = Descriptor::New(zone_, node->name(), type, Descriptor::Private);
54.933 - if (!desc)
54.934 - return;
54.935 - if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
54.936 - return;
54.937 - }
54.938 -
54.939 - void visitImportStatement(ImportStatement *node) {
54.940 - if (!node->names()) {
54.941 - PathComponent *path = node->path();
54.942 - while (path->next)
54.943 - path = path->next;
54.944 -
54.945 - // Imports automatically go into the importScope. For now, we
54.946 - // error if there are any duplicate symbols entered into the
54.947 - // importScope.
54.948 - if (unit_->importScope()->localLookup(path->name)) {
54.949 - cc_.reportError(node->pos(), Message_DuplicateImport, path->name->chars());
54.950 - return;
54.951 - }
54.952 -
54.953 - Local<Type> type(zone_, zone_->types()->getImportable());
54.954 - ImportSymbol *sym = new (pool_) ImportSymbol(unit_->importScope(), path->name, node->pos(), type, node->importIndex());
54.955 - if (!unit_->importScope()->addSymbol(sym))
54.956 - return;
54.957 - } else if (node->importAllNames()) {
54.958 - Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
54.959 - if (importable->isPackage()) {
54.960 - assert(false);
54.961 - } else {
54.962 - Local<Module> module(zone_, Module::cast(importable));
54.963 - if (!module->globals())
54.964 - importAllFromTranslationUnit(node, module->translationUnit());
54.965 - else
54.966 - assert(false);
54.967 - }
54.968 - } else {
54.969 - Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
54.970 - if (importable->isPackage()) {
54.971 - assert(false);
54.972 - } else {
54.973 - Local<Module> module(zone_, Module::cast(importable));
54.974 -
54.975 - // Always grab from the translation unit if we can, for now.
54.976 - if (module->translationUnit())
54.977 - importFromTranslationUnit(node, module->translationUnit());
54.978 - else
54.979 - assert(false);
54.980 - }
54.981 - }
54.982 - }
54.983 -
54.984 - private:
54.985 - bool importFrom(ImportStatement *node, Symbol *import) {
54.986 - assert(import->type());
54.987 -
54.988 - // Check for duplicate import names.
54.989 - if (unit_->importScope()->localLookup(import->name())) {
54.990 - cc_.reportError(node->pos(), Message_DuplicateImport, import->name()->chars());
54.991 - return false;
54.992 - }
54.993 -
54.994 - Symbol *sym;
54.995 - if (import->isType()) {
54.996 - // Fuck it, make a TypeSymbol instead of an ImplicitSymbol. This
54.997 - // makes bindType() much simpler. We may run into problems
54.998 - // implementing linking, but it seems unlikely, as long as we are
54.999 - // exporting Types in module structs.
54.1000 - Local<Type> type(zone_, zone_->types()->getType());
54.1001 - sym = new (pool_) TypeSymbol(unit_->importScope(),
54.1002 - import->name(),
54.1003 - type,
54.1004 - import->toType()->effective());
54.1005 - } else if (import->isConstant()) {
54.1006 - // Same deal. No reason to lookup in the module globals if we
54.1007 - // already have a symbol.
54.1008 - sym = new (pool_) ConstantSymbol(unit_->importScope(),
54.1009 - import->name(),
54.1010 - node->pos(),
54.1011 - import->type(),
54.1012 - import->toConstant()->value());
54.1013 - } else {
54.1014 - sym = new (pool_) ImplicitSymbol(unit_->importScope(),
54.1015 - import->name(),
54.1016 - node->pos(),
54.1017 - import->type(),
54.1018 - node->importIndex());
54.1019 - }
54.1020 -
54.1021 - if (!unit_->importScope()->addSymbol(sym))
54.1022 - return false;
54.1023 -
54.1024 - return true;
54.1025 - }
54.1026 -
54.1027 - void importFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
54.1028 - assert(!other->failed());
54.1029 -
54.1030 - for (size_t i = 0; i < node->names()->length(); i++) {
54.1031 - Handle<String> name = *node->names()->at(i);
54.1032 -
54.1033 - // See if the name exists in the other translation unit.
54.1034 - Symbol *import = other->globalScope()->findExported(name);
54.1035 - if (!import) {
54.1036 - FixedArray *path = unit_->module()->importPathAt(node->importIndex());
54.1037 - cc_.reportError(node->pos(), Message_NotFoundInImportable,
54.1038 - name->chars(),
54.1039 - String::cast(path->at(path->length() - 1))->chars());
54.1040 - return;
54.1041 - }
54.1042 -
54.1043 - if (!importFrom(node, import))
54.1044 - return;
54.1045 - }
54.1046 - }
54.1047 -
54.1048 - void importAllFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
54.1049 - assert(!other->failed());
54.1050 -
54.1051 - for (size_t i = 0; i < other->globalScope()->exported()->length(); i++) {
54.1052 - Symbol *import = other->globalScope()->exported()->at(i);
54.1053 - if (!importFrom(node, import))
54.1054 - return;
54.1055 - }
54.1056 - }
54.1057 -
54.1058 - private:
54.1059 - StructureBufferBuilder builder_;
54.1060 - Vector<ScopedRoot<Descriptor> *> descriptors_;
54.1061 - GlobalScope *globalScope_;
54.1062 - Vector<PrimitiveFill> primitiveFills_;
54.1063 -};
54.1064 -
54.1065 -class NameBinder : public NameBinderBase
54.1066 -{
54.1067 - public:
54.1068 - class AutoLinkScope
54.1069 - {
54.1070 - public:
54.1071 - AutoLinkScope(AutoLinkScope **prevp, Scope *scope)
54.1072 - : prevp_(prevp),
54.1073 - prev_(*prevp),
54.1074 - scope_(scope)
54.1075 - {
54.1076 - if (scope_) {
54.1077 - *prevp_ = this;
54.1078 - if (prev_)
54.1079 - scope_->setParent(prev_->scope());
54.1080 - }
54.1081 - }
54.1082 - ~AutoLinkScope() {
54.1083 - if (scope_) {
54.1084 - assert(*prevp_ == this);
54.1085 - *prevp_ = prev_;
54.1086 - }
54.1087 - }
54.1088 - Scope *scope() const {
54.1089 - return scope_;
54.1090 - }
54.1091 -
54.1092 - private:
54.1093 - AutoLinkScope **prevp_;
54.1094 - AutoLinkScope *prev_;
54.1095 - Scope *scope_;
54.1096 - };
54.1097 -
54.1098 - public:
54.1099 - NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.1100 - : NameBinderBase(zone, cc, unit),
54.1101 - link_(NULL)
54.1102 - {
54.1103 - }
54.1104 -
54.1105 - void bind() {
54.1106 - // Start with the import scope, and collect all imported names.
54.1107 - AutoLinkScope importScope(&link_, unit_->importScope());
54.1108 -
54.1109 - for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
54.1110 - unit_->tree()->imports()->at(i)->accept(this);
54.1111 -
54.1112 - // Next, enter the global scope and walk all statements.
54.1113 - AutoLinkScope globalScope(&link_, unit_->globalScope());
54.1114 - for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
54.1115 - Statement *stmt = unit_->tree()->statements()->at(i);
54.1116 - stmt->accept(this);
54.1117 - }
54.1118 - }
54.1119 -
54.1120 - void visitVariableDeclaration(VariableDeclaration *node) {
54.1121 - // Bind the initializer before registering the declaration, so that we
54.1122 - // can error on bogus initializers (new x = x).
54.1123 - if (node->initialization())
54.1124 - node->initialization()->accept(this);
54.1125 -
54.1126 - // If the node already has a symbol (meaning it was a global), then
54.1127 - // we don't have to do anything more.
54.1128 - if (node->sym())
54.1129 - return;
54.1130 -
54.1131 - Local<Type> type(zone_, buildVariableType(node));
54.1132 - if (!type)
54.1133 - return;
54.1134 -
54.1135 - VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type);
54.1136 - node->setSymbol(sym);
54.1137 -
54.1138 - if (Symbol *other = link_->scope()->localLookup(sym->name())) {
54.1139 - // Report, but allow errors to continue.
54.1140 - cc_.reportError(sym->pos(), Message_RedeclaredName,
54.1141 - sym->name()->chars(),
54.1142 - other->pos().line,
54.1143 - other->pos().col);
54.1144 - return;
54.1145 - }
54.1146 -
54.1147 - link_->scope()->addSymbol(sym);
54.1148 - }
54.1149 - void visitEnumStatement(EnumStatement *node) {
54.1150 - }
54.1151 - void visitFunctionStatement(FunctionStatement *node) {
54.1152 - AutoLinkScope argScope(&link_, node->argScope());
54.1153 - AutoLinkScope varScope(&link_, node->varScope());
54.1154 -
54.1155 - // If the function is in the global scope, we've already computed its
54.1156 - // type.
54.1157 - if (node->sym()->scope()->kind() != Scope::GLOBAL) {
54.1158 - Local<FunctionType> type(zone_, node->sym()->type());
54.1159 - if (!fillFunctionType(type, node->signature()))
54.1160 - return;
54.1161 - }
54.1162 -
54.1163 - if (node->body())
54.1164 - node->body()->accept(this);
54.1165 - }
54.1166 - void visitStructureStatement(StructureStatement *node) {
54.1167 - assert(false);
54.1168 - }
54.1169 - void visitFunctionTypeStatement(FunctionTypeStatement *node) {
54.1170 - assert(false);
54.1171 - }
54.1172 -
54.1173 - void visitNameProxy(NameProxy *proxy) {
54.1174 - // We could have already bound globals.
54.1175 - if (proxy->sym())
54.1176 - return;
54.1177 -
54.1178 - Scope *scope = link_->scope();
54.1179 - Symbol *sym = scope->lookup(proxy->name());
54.1180 - if (!sym)
54.1181 - cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
54.1182 - proxy->bind(sym);
54.1183 - }
54.1184 - void visitAssignment(Assignment *node) {
54.1185 - node->lvalue()->accept(this);
54.1186 - node->expression()->accept(this);
54.1187 - }
54.1188 - void visitBinaryExpression(BinaryExpression *node) {
54.1189 - node->left()->accept(this);
54.1190 - node->right()->accept(this);
54.1191 - }
54.1192 - void visitReturnStatement(ReturnStatement *node) {
54.1193 - node->expression()->accept(this);
54.1194 - }
54.1195 - void visitForStatement(ForStatement *node) {
54.1196 - AutoLinkScope scope(&link_, node->scope());
54.1197 -
54.1198 - if (node->initialization())
54.1199 - node->initialization()->accept(this);
54.1200 - if (node->condition())
54.1201 - node->condition()->accept(this);
54.1202 - if (node->update())
54.1203 - node->update()->accept(this);
54.1204 - node->body()->accept(this);
54.1205 - }
54.1206 - void visitBlockStatement(BlockStatement *node) {
54.1207 - AutoLinkScope scope(&link_, node->scope());
54.1208 - for (size_t i = 0; i < node->statements()->length(); i++)
54.1209 - node->statements()->at(i)->accept(this);
54.1210 - }
54.1211 - void visitIntegerLiteral(IntegerLiteral *node) {
54.1212 - }
54.1213 - void visitExpressionStatement(ExpressionStatement *node) {
54.1214 - node->expression()->accept(this);
54.1215 - }
54.1216 - void visitCallExpression(CallExpression *node) {
54.1217 - node->callee()->accept(this);
54.1218 - for (size_t i = 0; i < node->arguments()->length(); i++)
54.1219 - node->arguments()->at(i)->accept(this);
54.1220 - }
54.1221 - void visitIfStatement(IfStatement *node) {
54.1222 - node->condition()->accept(this);
54.1223 - node->ifTrue()->accept(this);
54.1224 - if (node->ifFalse())
54.1225 - node->ifFalse()->accept(this);
54.1226 - }
54.1227 - void visitIndexExpression(IndexExpression *node) {
54.1228 - node->left()->accept(this);
54.1229 - node->right()->accept(this);
54.1230 - }
54.1231 - void visitFloatLiteral(FloatLiteral *node) {
54.1232 - }
54.1233 - void visitWhileStatement(WhileStatement *node) {
54.1234 - node->condition()->accept(this);
54.1235 - node->body()->accept(this);
54.1236 - }
54.1237 - void visitBreakStatement(BreakStatement *node) {
54.1238 - }
54.1239 - void visitContinueStatement(ContinueStatement *node) {
54.1240 - }
54.1241 - void visitStringLiteral(StringLiteral *node) {
54.1242 - }
54.1243 - void visitIncDecExpression(IncDecExpression *node) {
54.1244 - node->expression()->accept(this);
54.1245 - }
54.1246 - void visitUnaryExpression(UnaryExpression *node) {
54.1247 - if (node->tag())
54.1248 - node->tag()->accept(this);
54.1249 - node->expression()->accept(this);
54.1250 - }
54.1251 - void visitTernaryExpression(TernaryExpression *node) {
54.1252 - node->condition()->accept(this);
54.1253 - node->left()->accept(this);
54.1254 - node->right()->accept(this);
54.1255 - }
54.1256 - void visitBooleanLiteral(BooleanLiteral *node) {
54.1257 - }
54.1258 - void visitFieldExpression(FieldExpression *node) {
54.1259 - node->left()->accept(this);
54.1260 - }
54.1261 - void visitSwitchStatement(SwitchStatement *node) {
54.1262 - node->expression()->accept(this);
54.1263 - node->defaultCase()->accept(this);
54.1264 - for (size_t i = 0; i < node->cases()->length(); i++) {
54.1265 - // We don't test case expressions because they are literals.
54.1266 - Case *c = node->cases()->at(i);
54.1267 - c->statement()->accept(this);
54.1268 - }
54.1269 - }
54.1270 - void visitArrayLiteral(ArrayLiteral *node) {
54.1271 - for (size_t i = 0; i < node->expressions()->length(); i++)
54.1272 - node->expressions()->at(i)->accept(this);
54.1273 - }
54.1274 - void visitImportStatement(ImportStatement *node) {
54.1275 - }
54.1276 -
54.1277 - private:
54.1278 - AutoLinkScope *link_;
54.1279 -};
54.1280 -
54.1281 -void
54.1282 -ke::BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.1283 -{
54.1284 - AutoEnterCompileContext enter(cc, unit);
54.1285 -
54.1286 - GlobalBuilder builder(zone, cc, unit);
54.1287 - Local<Struct> globals(zone, builder.build());
54.1288 - if (!globals || unit->failed())
54.1289 - return;
54.1290 -
54.1291 - unit->module()->setGlobals(globals);
54.1292 -}
54.1293 -
54.1294 -void
54.1295 -ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.1296 -{
54.1297 - AutoEnterCompileContext enter(cc, unit);
54.1298 - NameBinder binder(zone, cc, unit);
54.1299 - binder.bind();
54.1300 -}
54.1301 +/* vim: set ts=4 sw=4 tw=99 et:
54.1302 + *
54.1303 + * Copyright (C) 2012 David Anderson
54.1304 + *
54.1305 + * This file is part of SourcePawn.
54.1306 + *
54.1307 + * SourcePawn is free software: you can redistribute it and/or modify it under
54.1308 + * the terms of the GNU General Public License as published by the Free
54.1309 + * Software Foundation, either version 3 of the License, or (at your option)
54.1310 + * any later version.
54.1311 + *
54.1312 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
54.1313 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
54.1314 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
54.1315 + *
54.1316 + * You should have received a copy of the GNU General Public License along with
54.1317 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
54.1318 + */
54.1319 +#include "../Strings.h"
54.1320 +#include "../Zone.h"
54.1321 +#include "../TypeManager.h"
54.1322 +#include "NameBinding.h"
54.1323 +#include "Scopes.h"
54.1324 +#include "ConstantEvaluator.h"
54.1325 +#include "../Spaces-inl.h"
54.1326 +#include "../Heap-inl.h"
54.1327 +
54.1328 +using namespace ke;
54.1329 +
54.1330 +// Create symbol tables and symbols for every scope and declaration. For type
54.1331 +// declarations and methods, we also pre-allocate a Type object, so that
54.1332 +// circular dependencies between types will work.
54.1333 +class NamePopulator : public AstVisitor
54.1334 +{
54.1335 + private:
54.1336 + // This class is analagous to a Scope, however, it allows us to create
54.1337 + // scopes lazily. If a scope is requested, and the current environment
54.1338 + // has no scope, then a scope is created. If no scope is ever requested,
54.1339 + // a scope does not need to be created.
54.1340 + class SymbolEnv
54.1341 + {
54.1342 + public:
54.1343 + SymbolEnv(SymbolEnv **prevp, Scope *scope = NULL)
54.1344 + : envp_(prevp),
54.1345 + prev_(*prevp),
54.1346 + scope_(scope)
54.1347 + {
54.1348 + *envp_ = this;
54.1349 + }
54.1350 + ~SymbolEnv() {
54.1351 + *envp_ = prev_;
54.1352 + }
54.1353 +
54.1354 + Scope *scope() {
54.1355 + return scope_;
54.1356 + }
54.1357 + void setScope(Scope *scope) {
54.1358 + assert(!scope_);
54.1359 + scope_ = scope;
54.1360 + }
54.1361 + SymbolEnv *prev() const {
54.1362 + return prev_;
54.1363 + }
54.1364 +
54.1365 + private:
54.1366 + SymbolEnv **envp_;
54.1367 + SymbolEnv *prev_;
54.1368 + Scope *scope_;
54.1369 + };
54.1370 +
54.1371 + enum ReturnStatus {
54.1372 + NoReturn,
54.1373 + VoidReturn,
54.1374 + ValueReturn
54.1375 + };
54.1376 +
54.1377 + class FunctionScope
54.1378 + {
54.1379 + public:
54.1380 + FunctionScope(FunctionScope **prevp)
54.1381 + : prevp_(prevp),
54.1382 + prev_(*prevp),
54.1383 + status_(NoReturn)
54.1384 + {
54.1385 + *prevp_ = this;
54.1386 + }
54.1387 + ~FunctionScope() {
54.1388 + *prevp_ = prev_;
54.1389 + }
54.1390 + ReturnStatus returns() const {
54.1391 + return status_;
54.1392 + }
54.1393 + void returns(ReturnStatus status) {
54.1394 + if (status > status_)
54.1395 + status_ = status;
54.1396 + }
54.1397 + private:
54.1398 + FunctionScope **prevp_;
54.1399 + FunctionScope *prev_;
54.1400 + ReturnStatus status_;
54.1401 + };
54.1402 +
54.1403 + public:
54.1404 + NamePopulator(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.1405 + : zone_(zone),
54.1406 + pool_(zone->pool()),
54.1407 + cc_(cc),
54.1408 + unit_(unit),
54.1409 + env_(NULL),
54.1410 + fun_(NULL)
54.1411 + {
54.1412 + }
54.1413 +
54.1414 + void analyze() {
54.1415 + ImportScope *importScope = ImportScope::New(pool_);
54.1416 + if (!importScope)
54.1417 + return;
54.1418 +
54.1419 + // At the import level, we declare system types.
54.1420 + if (!declareSystemTypes(importScope))
54.1421 + return;
54.1422 +
54.1423 + GlobalScope *globalScope = GlobalScope::New(pool_, importScope);
54.1424 + if (!globalScope)
54.1425 + return;
54.1426 +
54.1427 + unit_->setImportScope(importScope);
54.1428 + unit_->setGlobalScope(globalScope);
54.1429 +
54.1430 + SymbolEnv env(&env_, globalScope);
54.1431 +
54.1432 + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
54.1433 + Statement *stmt = unit_->tree()->statements()->at(i);
54.1434 + stmt->accept(this);
54.1435 + }
54.1436 +
54.1437 + return;
54.1438 + }
54.1439 +
54.1440 + bool declareSystemType(ImportScope *scope, const char *name, Handle<Type> effective) {
54.1441 + Local<String> tag(zone_, zone_->makeSymbol(name));
54.1442 + if (!tag)
54.1443 + return false;
54.1444 +
54.1445 + Local<Type> type(zone_, zone_->types()->getType());
54.1446 +
54.1447 + TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type, effective);
54.1448 + return scope->addSymbol(sym);
54.1449 + }
54.1450 +
54.1451 + bool declareSystemType(ImportScope *scope, const char *name, PrimitiveType prim) {
54.1452 + Local<Type> primitive(zone_, zone_->types()->getPrimitive(prim));
54.1453 + assert(primitive);
54.1454 + return declareSystemType(scope, name, primitive);
54.1455 + }
54.1456 +
54.1457 + bool declareSystemTypes(ImportScope *scope) {
54.1458 + if (!declareSystemType(scope, "float", PrimitiveType_Float))
54.1459 + return false;
54.1460 + if (!declareSystemType(scope, "_", PrimitiveType_Int32))
54.1461 + return false;
54.1462 + if (!declareSystemType(scope, "int", PrimitiveType_Int32))
54.1463 + return false;
54.1464 + if (!declareSystemType(scope, "bool", PrimitiveType_Bool))
54.1465 + return false;
54.1466 + if (!declareSystemType(scope, "char", PrimitiveType_Char))
54.1467 + return false;
54.1468 +
54.1469 + Local<Type> voidType(zone_, zone_->types()->getVoid());
54.1470 + if (!declareSystemType(scope, "void", voidType))
54.1471 + return false;
54.1472 +
54.1473 + return true;
54.1474 + }
54.1475 +
54.1476 + void visitVariableDeclaration(VariableDeclaration *node) {
54.1477 + Scope *scope = env_->scope();
54.1478 + if (!scope || scope->kind() != Scope::GLOBAL) {
54.1479 + if ((scope = getOrCreateBlockScope()) == NULL)
54.1480 + return;
54.1481 + }
54.1482 +
54.1483 + if (scope->kind() == Scope::GLOBAL) {
54.1484 + // The symbol must be added now, since it could be an export.
54.1485 + VariableSymbol *sym = new (pool_) VariableSymbol(scope, node->name(), node->pos());
54.1486 + node->setSymbol(sym);
54.1487 +
54.1488 + if (!registerName(scope, sym))
54.1489 + return;
54.1490 + } else {
54.1491 + // We ensure the scope will exist at the name binding phase, but
54.1492 + // we don't actually register the variable symbol yet. Otherwise,
54.1493 + // when binding the initializer, we could encounter:
54.1494 + // new x = x;
54.1495 + //
54.1496 + // And we don't necessarily want this to bind.
54.1497 + }
54.1498 +
54.1499 + if (node->initialization())
54.1500 + node->initialization()->accept(this);
54.1501 + }
54.1502 +
54.1503 + void visitEnumStatement(EnumStatement *node) {
54.1504 + Local<String> name(zone_, node->name());
54.1505 + Local<Type> type(zone_);
54.1506 + if (name)
54.1507 + type = zone_->types()->newEnum(name);
54.1508 + else
54.1509 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
54.1510 +
54.1511 + if (!type)
54.1512 + return;
54.1513 +
54.1514 + Scope *scope = getGlobalOrCreateBlockScope();
54.1515 + if (!scope)
54.1516 + return;
54.1517 +
54.1518 + if (name) {
54.1519 + Local<Type> symType(zone_, zone_->types()->getType());
54.1520 + TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, symType, type);
54.1521 + if (!registerName(scope, sym))
54.1522 + return;
54.1523 +
54.1524 + if (scope->kind() == Scope::GLOBAL) {
54.1525 + if (!unit_->globalScope()->exported()->append(sym))
54.1526 + return;
54.1527 + }
54.1528 + }
54.1529 +
54.1530 + // We want each field of the expression to qualify as a constant expression.
54.1531 + if ((type = zone_->types()->qualify(type, TypeQual_ConstExpr)) == NULL)
54.1532 + return;
54.1533 +
54.1534 + int value = 0;
54.1535 + for (size_t i = 0; i < node->entries()->length(); i++) {
54.1536 + EnumStatement::Entry &entry = node->entries()->at(i);
54.1537 + BoxedPrimitive box = BoxedPrimitive::Int(value);
54.1538 + if (entry.expr) {
54.1539 + if (!EvaluateForConstant(entry.expr, &box) || box.type() != PrimitiveType_Int32) {
54.1540 + cc_.reportError(entry.expr->pos(), Message_EnumFieldNotConstant);
54.1541 + return;
54.1542 + }
54.1543 +
54.1544 + assert(box.type() == PrimitiveType_Int32);
54.1545 + value = box.toInt();
54.1546 + }
54.1547 +
54.1548 + ConstantSymbol *sym = new (pool_) ConstantSymbol(scope, entry.name, entry.pos, type, box);
54.1549 + if (!registerName(scope, sym))
54.1550 + return;
54.1551 + if (scope->kind() == Scope::GLOBAL) {
54.1552 + if (!unit_->globalScope()->exported()->append(sym))
54.1553 + return;
54.1554 + }
54.1555 +
54.1556 + entry.sym = sym;
54.1557 + value++;
54.1558 + }
54.1559 + }
54.1560 +
54.1561 + void visitFunctionStatement(FunctionStatement *node) {
54.1562 + // We create function types ahead of time, not for any particular
54.1563 + // reason. It makes things consistent with FunctionTypeStatement,
54.1564 + // which actually does produce a type.
54.1565 + Local<FunctionType> type(zone_, FunctionType::New(zone_, node->name(), node->token()));
54.1566 + if (!type)
54.1567 + return;
54.1568 +
54.1569 + assert(env_->scope());
54.1570 +
54.1571 + // Function statements are always named, so add the name to the outer scope.
54.1572 + FunctionSymbol *sym = new (pool_) FunctionSymbol(env_->scope(), node->name(), node->pos(), type);
54.1573 + if (!registerName(env_->scope(), sym))
54.1574 + return;
54.1575 +
54.1576 + if (node->token() == TOK_PUBLIC ||
54.1577 + node->token() == TOK_FORWARD ||
54.1578 + node->token() == TOK_NATIVE)
54.1579 + {
54.1580 + // We're in the global scope, for sure.
54.1581 + assert(env_->scope()->kind() == Scope::GLOBAL);
54.1582 +
54.1583 + if (!unit_->globalScope()->exported()->append(sym))
54.1584 + return;
54.1585 + }
54.1586 +
54.1587 + node->setSymbol(sym);
54.1588 +
54.1589 + // Scope for the function's arguments.
54.1590 + SymbolEnv argEnv(&env_);
54.1591 + if (!registerArguments(node->signature()))
54.1592 + return;
54.1593 +
54.1594 + // Scope for function body.
54.1595 + SymbolEnv localEnv(&env_);
54.1596 + FunctionScope fun(&fun_);
54.1597 + if (node->body())
54.1598 + node->body()->accept(this);
54.1599 +
54.1600 + // Function statements have quirky semantics around their return
54.1601 + // type. For reasonable compatibility with SP1, we use the following
54.1602 + // heuristics for when no explicit type is declared.
54.1603 + if (!node->signature().returnType()) {
54.1604 + Local<Type> type(zone_);
54.1605 + if (node->token() == TOK_FORWARD || node->token() == TOK_NATIVE) {
54.1606 + // If the function type is a native or forward, we always
54.1607 + // assume it returns an int32.
54.1608 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
54.1609 + } else if (fun.returns() != ValueReturn) {
54.1610 + // This function never returns a value, so mark it as
54.1611 + // returning void.
54.1612 + type = zone_->types()->getVoid();
54.1613 + }
54.1614 + // No need to NULL check here, we'll catch OOM later.
54.1615 + node->sym()->type()->setReturnType(type);
54.1616 + }
54.1617 +
54.1618 + node->setScopes(argEnv.scope(), localEnv.scope());
54.1619 + }
54.1620 +
54.1621 + void visitStructureStatement(StructureStatement *node) {
54.1622 + assert(false);
54.1623 + }
54.1624 +
54.1625 + void visiFunctionTypeStatementt(FunctionTypeStatement *node) {
54.1626 + assert(false);
54.1627 + }
54.1628 +
54.1629 + void visitNameProxy(NameProxy *name) {
54.1630 + }
54.1631 + void visitAssignment(Assignment *node) {
54.1632 + node->lvalue()->accept(this);
54.1633 + node->expression()->accept(this);
54.1634 + }
54.1635 + void visitBinaryExpression(BinaryExpression *node) {
54.1636 + node->left()->accept(this);
54.1637 + node->right()->accept(this);
54.1638 + }
54.1639 + void visitReturnStatement(ReturnStatement *node) {
54.1640 + if (node->expression())
54.1641 + fun_->returns(ValueReturn);
54.1642 + else
54.1643 + fun_->returns(VoidReturn);
54.1644 + }
54.1645 + void visitForStatement(ForStatement *node) {
54.1646 + SymbolEnv env(&env_);
54.1647 +
54.1648 + if (node->initialization())
54.1649 + node->initialization()->accept(this);
54.1650 + if (node->condition())
54.1651 + node->condition()->accept(this);
54.1652 + if (node->update())
54.1653 + node->update()->accept(this);
54.1654 + node->body()->accept(this);
54.1655 +
54.1656 + node->setScope(env.scope());
54.1657 + }
54.1658 + void visitBlockStatement(BlockStatement *node) {
54.1659 + if (node->type() == TOK_NEW) {
54.1660 + // Don't create a symbol environment for this block, since it
54.1661 + // was created solely to house multiple variable decls.
54.1662 + for (size_t i = 0; i < node->statements()->length(); i++)
54.1663 + node->statements()->at(i)->accept(this);
54.1664 + } else {
54.1665 + assert(node->type() == TOK_LBRACE);
54.1666 +
54.1667 + SymbolEnv env(&env_);
54.1668 +
54.1669 + for (size_t i = 0; i < node->statements()->length(); i++)
54.1670 + node->statements()->at(i)->accept(this);
54.1671 +
54.1672 + if (node->type() == TOK_NEW) {
54.1673 + assert(!env.scope());
54.1674 + return;
54.1675 + }
54.1676 +
54.1677 + node->setScope(env.scope());
54.1678 + }
54.1679 + }
54.1680 + void visitIntegerLiteral(IntegerLiteral *node) {
54.1681 + }
54.1682 + void visitExpressionStatement(ExpressionStatement *node) {
54.1683 + node->expression()->accept(this);
54.1684 + }
54.1685 + void visitCallExpression(CallExpression *node) {
54.1686 + node->callee()->accept(this);
54.1687 + for (size_t i = 0; i < node->arguments()->length(); i++)
54.1688 + node->arguments()->at(i)->accept(this);
54.1689 + }
54.1690 + void visitIfStatement(IfStatement *node) {
54.1691 + node->ifTrue()->accept(this);
54.1692 + if (node->ifFalse())
54.1693 + node->ifFalse()->accept(this);
54.1694 + }
54.1695 + void visitIndexExpression(IndexExpression *node) {
54.1696 + node->left()->accept(this);
54.1697 + node->right()->accept(this);
54.1698 + }
54.1699 + void visitFloatLiteral(FloatLiteral *node) {
54.1700 + }
54.1701 + void visitWhileStatement(WhileStatement *node) {
54.1702 + node->condition()->accept(this);
54.1703 + node->body()->accept(this);
54.1704 + }
54.1705 + void visitBreakStatement(BreakStatement *node) {
54.1706 + }
54.1707 + void visitContinueStatement(ContinueStatement *node) {
54.1708 + }
54.1709 + void visitStringLiteral(StringLiteral *node) {
54.1710 + }
54.1711 + void visitIncDecExpression(IncDecExpression *node) {
54.1712 + node->expression()->accept(this);
54.1713 + }
54.1714 + void visitUnaryExpression(UnaryExpression *node) {
54.1715 + node->expression()->accept(this);
54.1716 + }
54.1717 + void visitTernaryExpression(TernaryExpression *node) {
54.1718 + assert(false);
54.1719 + }
54.1720 + void visitBooleanLiteral(BooleanLiteral *node) {
54.1721 + }
54.1722 + void visitFieldExpression(FieldExpression *node) {
54.1723 + }
54.1724 + void visitSwitchStatement(SwitchStatement *node) {
54.1725 + if (node->defaultCase())
54.1726 + node->defaultCase()->accept(this);
54.1727 +
54.1728 + for (size_t i = 0; i < node->cases()->length(); i++)
54.1729 + node->cases()->at(i)->statement()->accept(this);
54.1730 + }
54.1731 + void visitArrayLiteral(ArrayLiteral *node) {
54.1732 + }
54.1733 + void visitImportStatement(ImportStatement *node) {
54.1734 + }
54.1735 +
54.1736 + private:
54.1737 + Scope *getGlobalOrCreateBlockScope() {
54.1738 + if (env_->scope()) {
54.1739 + assert(env_->scope()->kind() == Scope::BLOCK ||
54.1740 + env_->scope()->kind() == Scope::GLOBAL);
54.1741 + return env_->scope();
54.1742 + }
54.1743 + return getOrCreateBlockScope();
54.1744 + }
54.1745 + Scope *getOrCreateBlockScope() {
54.1746 + if (env_->scope()) {
54.1747 + assert(env_->scope()->kind() == Scope::BLOCK);
54.1748 + return env_->scope();
54.1749 + }
54.1750 +
54.1751 + LocalScope *scope = LocalScope::New(pool_);
54.1752 + if (!scope)
54.1753 + return NULL;
54.1754 +
54.1755 + env_->setScope(scope);
54.1756 + return scope;
54.1757 + }
54.1758 +
54.1759 + bool registerName(Scope *scope, Symbol *sym) {
54.1760 + if (!scope)
54.1761 + return false;
54.1762 +
54.1763 + if (Symbol *other = scope->localLookup(sym->name())) {
54.1764 + // Report, but allow errors to continue.
54.1765 + cc_.reportError(sym->pos(), Message_RedeclaredName,
54.1766 + sym->name()->chars(),
54.1767 + other->pos().line,
54.1768 + other->pos().col);
54.1769 + return true;
54.1770 + }
54.1771 +
54.1772 + return scope->addSymbol(sym);
54.1773 + }
54.1774 +
54.1775 + bool registerArguments(const FunctionSignature &sig) {
54.1776 + if (!sig.parameters()->length())
54.1777 + return true;
54.1778 +
54.1779 + ArgumentScope *argScope = ArgumentScope::New(pool_);
54.1780 + if (!argScope)
54.1781 + return false;
54.1782 + env_->setScope(argScope);
54.1783 +
54.1784 + for (size_t i = 0; i < sig.parameters()->length(); i++) {
54.1785 + Parameter *param = sig.parameters()->at(i);
54.1786 + VariableSymbol *sym = new (pool_) VariableSymbol(argScope, param->name(), param->pos());
54.1787 + if (!registerName(env_->scope(), sym))
54.1788 + return false;
54.1789 + param->setSymbol(sym);
54.1790 + }
54.1791 +
54.1792 + return true;
54.1793 + }
54.1794 +
54.1795 + private:
54.1796 + Zone *zone_;
54.1797 + PoolAllocator &pool_;
54.1798 + CompileContext &cc_;
54.1799 + TranslationUnit *unit_;
54.1800 + SymbolEnv *env_;
54.1801 + FunctionScope *fun_;
54.1802 +};
54.1803 +
54.1804 +void
54.1805 +ke::PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.1806 +{
54.1807 + AutoEnterCompileContext enter(cc, unit);
54.1808 + NamePopulator populator(zone, cc, unit);
54.1809 + populator.analyze();
54.1810 +}
54.1811 +
54.1812 +static const int INFER_ARRAY_SIZE = 0;
54.1813 +static const int EVAL_ARRAY_SIZE = -1;
54.1814 +static const int DYNAMIC_ARRAY_SIZE = -2;
54.1815 +
54.1816 +class NameBinderBase : public AstVisitor
54.1817 +{
54.1818 + public:
54.1819 + NameBinderBase(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.1820 + : zone_(zone),
54.1821 + pool_(zone->pool()),
54.1822 + cc_(cc),
54.1823 + unit_(unit)
54.1824 + {
54.1825 + }
54.1826 +
54.1827 + protected:
54.1828 + Type *buildVariableType(VariableDeclaration *node) {
54.1829 + Local<Type> type(zone_, bindType(node->type(), node->quals()));
54.1830 + if (!type)
54.1831 + return NULL;
54.1832 +
54.1833 + // We don't allow array typedefs yet.
54.1834 + assert(!type->isArray());
54.1835 +
54.1836 + if (node->dims()) {
54.1837 + int dims[MAX_ARRAY_DEPTH];
54.1838 + int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
54.1839 + if (levels < 0)
54.1840 + return NULL;
54.1841 +
54.1842 + // Do some extra inference based on the initializer, if present.
54.1843 + Expression *init = node->initialization();
54.1844 + if (init) {
54.1845 + if (init->isArrayLiteral() && init->toArrayLiteral()->isFixed()) {
54.1846 + Local<Type> contained(zone_, type->isArray()
54.1847 + ? ArrayType::cast(type)->contained()
54.1848 + : type);
54.1849 + if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels))
54.1850 + return NULL;
54.1851 + } else if (init->isStringLiteral()) {
54.1852 + dims[levels - 1] = init->toStringLiteral()->string()->length() + 1;
54.1853 + }
54.1854 + }
54.1855 +
54.1856 + // If we got extra dimensions, we need to build a new type.
54.1857 + if (node->dims()) {
54.1858 + if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL)
54.1859 + return NULL;
54.1860 + }
54.1861 + }
54.1862 +
54.1863 + return type;
54.1864 + }
54.1865 +
54.1866 + int evaluateDimensions(const SourcePosition &pos, Handle<Type> typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) {
54.1867 + unsigned level = 0;
54.1868 + Local<Type> type(zone_, typeArg);
54.1869 + while (type->isArray()) {
54.1870 + ArrayType *atype = ArrayType::cast(type);
54.1871 + dims[level] = atype->isFixedLength()
54.1872 + ? atype->fixedLength()
54.1873 + : DYNAMIC_ARRAY_SIZE;
54.1874 + type = atype->contained();
54.1875 + level++;
54.1876 + }
54.1877 +
54.1878 + if (!exprs)
54.1879 + return level;
54.1880 +
54.1881 + if (level + exprs->length() > MAX_ARRAY_DEPTH) {
54.1882 + cc_.reportError(pos, Message_MaximumArrayDepth);
54.1883 + return -1;
54.1884 + }
54.1885 +
54.1886 + bool hadEmptySize = false;
54.1887 + for (size_t i = 0; i < exprs->length(); i++) {
54.1888 + Expression *expr = exprs->at(i);
54.1889 + if (!expr) {
54.1890 + dims[i] = INFER_ARRAY_SIZE;
54.1891 + hadEmptySize = true;
54.1892 + continue;
54.1893 + }
54.1894 +
54.1895 + BoxedPrimitive box;
54.1896 + if (EvaluateForConstant(expr, &box) && box.type() == PrimitiveType_Int32) {
54.1897 + int size = box.toInt();
54.1898 + if (size <= 0) {
54.1899 + cc_.reportError(expr->pos(), Message_BadArraySize);
54.1900 + return false;
54.1901 + }
54.1902 +
54.1903 + dims[i] = size;
54.1904 + continue;
54.1905 + }
54.1906 +
54.1907 + if (hadEmptySize) {
54.1908 + cc_.reportError(expr->pos(), Message_BadDynamicInitializer);
54.1909 + return false;
54.1910 + }
54.1911 +
54.1912 + dims[i] = EVAL_ARRAY_SIZE;
54.1913 + }
54.1914 +
54.1915 + return level + exprs->length();
54.1916 + }
54.1917 +
54.1918 + // This function computes missing dimension sizes based on a literal
54.1919 + // initializer. We don't really handle any size rules here; we just
54.1920 + // do a really dumb inference.
54.1921 + bool inferFixedArrayDimensions(ArrayLiteral *lit, Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], int levels) {
54.1922 + for (int i = 0; i < levels; i++) {
54.1923 + if (dims[i] == EVAL_ARRAY_SIZE || dims[i] == DYNAMIC_ARRAY_SIZE) {
54.1924 + // The following are invalid:
54.1925 + // new x[<expr>] = {...}
54.1926 + // new Type:x = {...} // where Type is a non-fixed array type
54.1927 + cc_.reportError(lit->pos(), Message_CannotInitializeEvalArray);
54.1928 + return false;
54.1929 + }
54.1930 +
54.1931 + if (dims[i] == INFER_ARRAY_SIZE) {
54.1932 + // Character arrays are always dynamic when inferred from string literals.
54.1933 + if (i == levels - 1 && contained->isChar())
54.1934 + dims[i] = DYNAMIC_ARRAY_SIZE;
54.1935 + else
54.1936 + dims[i] = lit->expressions()->length();
54.1937 + }
54.1938 +
54.1939 + if (i != levels - 1) {
54.1940 + // Fixed array literals are guaranteed to have at least one expression.
54.1941 + Expression *next = lit->expressions()->at(0);
54.1942 + if (!next->isArrayLiteral()) {
54.1943 + // Whelp... this array is just malformed. Not the best error message
54.1944 + // but whatever.
54.1945 + cc_.reportError(next->pos(), Message_ArraySizeCannotBeDetermined);
54.1946 + return false;
54.1947 + }
54.1948 + lit = next->toArrayLiteral();
54.1949 + }
54.1950 + }
54.1951 +
54.1952 + return true;
54.1953 + }
54.1954 +
54.1955 + ArrayType *buildArrayType(Handle<Type> contained, TypeQualifiers quals, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
54.1956 + Local<Type> type(zone_, contained);
54.1957 +
54.1958 + for (size_t i = postlevels - 1; i < postlevels; i--) {
54.1959 + int size = dims[i] > 0
54.1960 + ? dims[i]
54.1961 + : ArrayType::DYNAMIC_ARRAY_SIZE;
54.1962 +
54.1963 + if ((type = zone_->types()->newArray(contained, size)) == NULL)
54.1964 + return NULL;
54.1965 + if ((type = zone_->types()->qualify(type, quals)) == NULL)
54.1966 + return NULL;
54.1967 + }
54.1968 + return ArrayType::cast(type);
54.1969 + }
54.1970 +
54.1971 + bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
54.1972 + Local<Type> type(zone_);
54.1973 + if (!fun->returnType()) {
54.1974 + if ((type = bindType(sig.returnType(), TypeQual_None)) == NULL)
54.1975 + return false;
54.1976 + fun->setReturnType(type);
54.1977 + }
54.1978 +
54.1979 + if (sig.variadic())
54.1980 + fun->setVariadic();
54.1981 +
54.1982 + Local<FixedArray> params(zone_, FixedArray::New(zone_, sig.parameters()->length(), Heap::Tenure_Old));
54.1983 + if (!params)
54.1984 + return false;
54.1985 +
54.1986 + for (size_t i = 0; i < sig.parameters()->length(); i++) {
54.1987 + Parameter *param = sig.parameters()->at(i);
54.1988 + if ((type = bindType(param->type(), param->quals())) == NULL)
54.1989 + return false;
54.1990 +
54.1991 + assert(!type->isArray());
54.1992 +
54.1993 + if (param->dims()) {
54.1994 + int dims[MAX_ARRAY_DEPTH];
54.1995 + int levels = evaluateDimensions(param->pos(), type, param->dims(), dims);
54.1996 + if (levels < 0)
54.1997 + return false;
54.1998 +
54.1999 + // If we got extra dimensions, we need to build a new type.
54.2000 + // Unlike variables, we do not infer anything about array
54.2001 + // sizes from its default initializer.
54.2002 + if (param->dims()) {
54.2003 + if ((type = buildArrayType(type, param->quals(), dims, param->dims()->length())) == NULL)
54.2004 + return false;
54.2005 + }
54.2006 +
54.2007 + if (ArrayType::cast(type)->innermost()->isVoid()) {
54.2008 + cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
54.2009 + return false;
54.2010 + }
54.2011 + }
54.2012 +
54.2013 + if (param->reference()) {
54.2014 + if (!type->isPod()) {
54.2015 + cc_.reportError(param->pos(), Message_ArrayCantBeReference);
54.2016 + return false;
54.2017 + }
54.2018 + if (param->quals() & TypeQual_Const) {
54.2019 + cc_.reportError(param->pos(), Message_CannotConstReference);
54.2020 + return false;
54.2021 + }
54.2022 + if ((type = zone_->types()->getReference(type, false)) == NULL)
54.2023 + return false;
54.2024 + }
54.2025 + if (param->quals() & TypeQual_Const) {
54.2026 + if (!type->isArray() && !type->isStruct()) {
54.2027 + cc_.reportError(param->pos(), Message_InvalidConstOnFormal);
54.2028 + return false;
54.2029 + }
54.2030 + }
54.2031 +
54.2032 + if (type->isVoid()) {
54.2033 + cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
54.2034 + return false;
54.2035 + }
54.2036 +
54.2037 + params->set(zone_, i, type);
54.2038 + param->sym()->setType(type);
54.2039 + }
54.2040 +
54.2041 + fun->setParameterTypes(params);
54.2042 +
54.2043 + return true;
54.2044 + }
54.2045 +
54.2046 + Type *bindType(Expression *expr, TypeQualifiers quals) {
54.2047 + Local<Type> type(zone_);
54.2048 +
54.2049 + if (!expr) {
54.2050 + // If no type was declared, we return int32.
54.2051 + type = zone_->types()->getPrimitive(PrimitiveType_Int32);
54.2052 + } else {
54.2053 + expr->accept(this);
54.2054 +
54.2055 + NameProxy *proxy = expr->asNameProxy();
54.2056 + assert(proxy);
54.2057 +
54.2058 + Symbol *sym = proxy->sym();
54.2059 + if (!sym)
54.2060 + return NULL;
54.2061 +
54.2062 + if (!sym->isType()) {
54.2063 + cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
54.2064 + return NULL;
54.2065 + }
54.2066 +
54.2067 + type = sym->toType()->effective();
54.2068 + }
54.2069 +
54.2070 + return zone_->types()->qualify(type, quals);
54.2071 + }
54.2072 +
54.2073 + protected:
54.2074 + Zone *zone_;
54.2075 + PoolAllocator &pool_;
54.2076 + CompileContext &cc_;
54.2077 + TranslationUnit *unit_;
54.2078 +};
54.2079 +
54.2080 +class GlobalBuilder : public NameBinderBase
54.2081 +{
54.2082 + typedef ScopedRoot<Descriptor> ScopedDescriptor;
54.2083 + struct PrimitiveFill {
54.2084 + ScopedDescriptor *desc;
54.2085 + BoxedPrimitive prim;
54.2086 +
54.2087 + PrimitiveFill(ScopedDescriptor *desc, BoxedPrimitive prim)
54.2088 + : desc(desc),
54.2089 + prim(prim)
54.2090 + {
54.2091 + }
54.2092 + };
54.2093 +
54.2094 + public:
54.2095 + GlobalBuilder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.2096 + : NameBinderBase(zone, cc, unit),
54.2097 + globalScope_(unit->globalScope())
54.2098 + {
54.2099 + }
54.2100 +
54.2101 + Struct *build() {
54.2102 + for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
54.2103 + unit_->tree()->imports()->at(i)->accept(this);
54.2104 +
54.2105 + // Next, enter the global scope and walk all statements.
54.2106 + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
54.2107 + Statement *stmt = unit_->tree()->statements()->at(i);
54.2108 + stmt->accept(this);
54.2109 + }
54.2110 +
54.2111 + Local<Struct> globals(zone_, createGlobals());
54.2112 + if (!globals)
54.2113 + return NULL;
54.2114 +
54.2115 + populate(globals);
54.2116 +
54.2117 + return globals;
54.2118 + }
54.2119 +
54.2120 + private:
54.2121 + Struct *createGlobals() {
54.2122 + Local<FixedArray> descs(zone_, FixedArray::New(zone_, descriptors_.length(), Heap::Tenure_Old));
54.2123 + if (!descs)
54.2124 + return NULL;
54.2125 +
54.2126 + for (unsigned i = 0; i < descriptors_.length(); i++)
54.2127 + descs->set(zone_, i, *descriptors_[i]);
54.2128 +
54.2129 + Local<String> name(zone_, unit_->module()->name());
54.2130 + Local<StructType> type(zone_, StructType::New(zone_, name, descs));
54.2131 + if (!type)
54.2132 + return NULL;
54.2133 +
54.2134 + Local<StructMap> map(zone_, type->newMap());
54.2135 + return Struct::New(zone_, map, Heap::Tenure_Old);
54.2136 + }
54.2137 +
54.2138 + void populate(Handle<Struct> globals) {
54.2139 + // This is a huge hack, but it's probably better than a full extra
54.2140 + // pass. The problem is that until we have all the descriptors, we
54.2141 + // can't start setting constexprs in the struct, and we need to set
54.2142 + // them now so they're available during full semantic analysis. To
54.2143 + // work around this, we build up the list of values we need to set
54.2144 + // as we build up descriptors, and then populate the global struct
54.2145 + // with this set.
54.2146 + //
54.2147 + // Note, this code is also kind of dead until we support linking. We
54.2148 + // handle constexprs explicitly in importFrom(), by sniffing out the
54.2149 + // symbol type. That code will go away later.
54.2150 + for (size_t i = 0; i < primitiveFills_.length(); i++) {
54.2151 + const PrimitiveFill &fill = primitiveFills_[i];
54.2152 + assert(fill.prim.type() == PrimitiveType_Int32);
54.2153 + globals->set(*fill.desc, fill.prim.toInt());
54.2154 + }
54.2155 + }
54.2156 +
54.2157 + public:
54.2158 + void visitEnumStatement(EnumStatement *stmt) {
54.2159 + if (stmt->visibility() != TOK_PUBLIC || !stmt->name())
54.2160 + return;
54.2161 +
54.2162 + Local<Type> type(zone_, zone_->types()->getType());
54.2163 + Descriptor *desc = Descriptor::New(zone_, stmt->name(), type, Descriptor::Public);
54.2164 + if (!desc)
54.2165 + return;
54.2166 + if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
54.2167 + return;
54.2168 +
54.2169 + for (size_t i = 0; i < stmt->entries()->length(); i++) {
54.2170 + EnumStatement::Entry &e = stmt->entries()->at(i);
54.2171 + ScopedDescriptor *desc = new (pool_) ScopedDescriptor(Descriptor::New(zone_, e.name, e.sym->type(), Descriptor::Public));
54.2172 + if (!desc || !descriptors_.append(desc))
54.2173 + return;
54.2174 +
54.2175 + // Save the value so we can export it immediately.
54.2176 + if (!primitiveFills_.append(PrimitiveFill(desc, e.sym->value())))
54.2177 + return;
54.2178 + }
54.2179 + }
54.2180 +
54.2181 + void visitNameProxy(NameProxy *proxy) {
54.2182 + Scope *scope = unit_->globalScope();
54.2183 + Symbol *sym = scope->lookup(proxy->name());
54.2184 + if (!sym)
54.2185 + cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
54.2186 + proxy->bind(sym);
54.2187 + }
54.2188 +
54.2189 + void visitFunctionStatement(FunctionStatement *node) {
54.2190 + Local<FunctionType> type(zone_, node->sym()->type());
54.2191 + if (!fillFunctionType(type, node->signature()))
54.2192 + return;
54.2193 +
54.2194 + unsigned offset;
54.2195 + if (!builder_.add(type, &offset))
54.2196 + return;
54.2197 +
54.2198 + Descriptor::Visibility visibility = (node->token() == TOK_NATIVE || node->token() == TOK_FORWARD)
54.2199 + ? Descriptor::Public
54.2200 + : Descriptor::Private;
54.2201 +
54.2202 + Descriptor *desc = Descriptor::New(zone_, node->name(), type, visibility);
54.2203 + if (!desc)
54.2204 + return;
54.2205 + if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
54.2206 + return;
54.2207 + }
54.2208 +
54.2209 + void visitVariableDeclaration(VariableDeclaration *node) {
54.2210 + Local<Type> type(zone_, buildVariableType(node));
54.2211 + if (!type)
54.2212 + return;
54.2213 +
54.2214 + // If we're in global scope, and we received a |const| qualifier, then
54.2215 + // we extend this to array references as well. This is to sort of mimic
54.2216 + // SP1 functionality, but also means that you cannot have changeable
54.2217 + // const pointers in global scope.
54.2218 + if ((node->quals() & TypeQual_Const) && type->isArray()) {
54.2219 + if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL)
54.2220 + return;
54.2221 + }
54.2222 +
54.2223 + node->sym()->setType(type);
54.2224 +
54.2225 + unsigned offset;
54.2226 + if (!builder_.add(type, &offset))
54.2227 + return;
54.2228 +
54.2229 + Descriptor *desc = Descriptor::New(zone_, node->name(), type, Descriptor::Private);
54.2230 + if (!desc)
54.2231 + return;
54.2232 + if (!descriptors_.append(new (pool_) ScopedRoot<Descriptor>(desc)))
54.2233 + return;
54.2234 + }
54.2235 +
54.2236 + void visitImportStatement(ImportStatement *node) {
54.2237 + if (!node->names()) {
54.2238 + PathComponent *path = node->path();
54.2239 + while (path->next)
54.2240 + path = path->next;
54.2241 +
54.2242 + // Imports automatically go into the importScope. For now, we
54.2243 + // error if there are any duplicate symbols entered into the
54.2244 + // importScope.
54.2245 + if (unit_->importScope()->localLookup(path->name)) {
54.2246 + cc_.reportError(node->pos(), Message_DuplicateImport, path->name->chars());
54.2247 + return;
54.2248 + }
54.2249 +
54.2250 + Local<Type> type(zone_, zone_->types()->getImportable());
54.2251 + ImportSymbol *sym = new (pool_) ImportSymbol(unit_->importScope(), path->name, node->pos(), type, node->importIndex());
54.2252 + if (!unit_->importScope()->addSymbol(sym))
54.2253 + return;
54.2254 + } else if (node->importAllNames()) {
54.2255 + Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
54.2256 + if (importable->isPackage()) {
54.2257 + assert(false);
54.2258 + } else {
54.2259 + Local<Module> module(zone_, Module::cast(importable));
54.2260 + if (!module->globals())
54.2261 + importAllFromTranslationUnit(node, module->translationUnit());
54.2262 + else
54.2263 + assert(false);
54.2264 + }
54.2265 + } else {
54.2266 + Local<Importable> importable(zone_, unit_->module()->getImportAt(node->importIndex()));
54.2267 + if (importable->isPackage()) {
54.2268 + assert(false);
54.2269 + } else {
54.2270 + Local<Module> module(zone_, Module::cast(importable));
54.2271 +
54.2272 + // Always grab from the translation unit if we can, for now.
54.2273 + if (module->translationUnit())
54.2274 + importFromTranslationUnit(node, module->translationUnit());
54.2275 + else
54.2276 + assert(false);
54.2277 + }
54.2278 + }
54.2279 + }
54.2280 +
54.2281 + private:
54.2282 + bool importFrom(ImportStatement *node, Symbol *import) {
54.2283 + assert(import->type());
54.2284 +
54.2285 + // Check for duplicate import names.
54.2286 + if (unit_->importScope()->localLookup(import->name())) {
54.2287 + cc_.reportError(node->pos(), Message_DuplicateImport, import->name()->chars());
54.2288 + return false;
54.2289 + }
54.2290 +
54.2291 + Symbol *sym;
54.2292 + if (import->isType()) {
54.2293 + // Fuck it, make a TypeSymbol instead of an ImplicitSymbol. This
54.2294 + // makes bindType() much simpler. We may run into problems
54.2295 + // implementing linking, but it seems unlikely, as long as we are
54.2296 + // exporting Types in module structs.
54.2297 + Local<Type> type(zone_, zone_->types()->getType());
54.2298 + sym = new (pool_) TypeSymbol(unit_->importScope(),
54.2299 + import->name(),
54.2300 + type,
54.2301 + import->toType()->effective());
54.2302 + } else if (import->isConstant()) {
54.2303 + // Same deal. No reason to lookup in the module globals if we
54.2304 + // already have a symbol.
54.2305 + sym = new (pool_) ConstantSymbol(unit_->importScope(),
54.2306 + import->name(),
54.2307 + node->pos(),
54.2308 + import->type(),
54.2309 + import->toConstant()->value());
54.2310 + } else {
54.2311 + sym = new (pool_) ImplicitSymbol(unit_->importScope(),
54.2312 + import->name(),
54.2313 + node->pos(),
54.2314 + import->type(),
54.2315 + node->importIndex());
54.2316 + }
54.2317 +
54.2318 + if (!unit_->importScope()->addSymbol(sym))
54.2319 + return false;
54.2320 +
54.2321 + return true;
54.2322 + }
54.2323 +
54.2324 + void importFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
54.2325 + assert(!other->failed());
54.2326 +
54.2327 + for (size_t i = 0; i < node->names()->length(); i++) {
54.2328 + Handle<String> name = *node->names()->at(i);
54.2329 +
54.2330 + // See if the name exists in the other translation unit.
54.2331 + Symbol *import = other->globalScope()->findExported(name);
54.2332 + if (!import) {
54.2333 + FixedArray *path = unit_->module()->importPathAt(node->importIndex());
54.2334 + cc_.reportError(node->pos(), Message_NotFoundInImportable,
54.2335 + name->chars(),
54.2336 + String::cast(path->at(path->length() - 1))->chars());
54.2337 + return;
54.2338 + }
54.2339 +
54.2340 + if (!importFrom(node, import))
54.2341 + return;
54.2342 + }
54.2343 + }
54.2344 +
54.2345 + void importAllFromTranslationUnit(ImportStatement *node, TranslationUnit *other) {
54.2346 + assert(!other->failed());
54.2347 +
54.2348 + for (size_t i = 0; i < other->globalScope()->exported()->length(); i++) {
54.2349 + Symbol *import = other->globalScope()->exported()->at(i);
54.2350 + if (!importFrom(node, import))
54.2351 + return;
54.2352 + }
54.2353 + }
54.2354 +
54.2355 + private:
54.2356 + StructureBufferBuilder builder_;
54.2357 + Vector<ScopedRoot<Descriptor> *> descriptors_;
54.2358 + GlobalScope *globalScope_;
54.2359 + Vector<PrimitiveFill> primitiveFills_;
54.2360 +};
54.2361 +
54.2362 +class NameBinder : public NameBinderBase
54.2363 +{
54.2364 + public:
54.2365 + class AutoLinkScope
54.2366 + {
54.2367 + public:
54.2368 + AutoLinkScope(AutoLinkScope **prevp, Scope *scope)
54.2369 + : prevp_(prevp),
54.2370 + prev_(*prevp),
54.2371 + scope_(scope)
54.2372 + {
54.2373 + if (scope_) {
54.2374 + *prevp_ = this;
54.2375 + if (prev_)
54.2376 + scope_->setParent(prev_->scope());
54.2377 + }
54.2378 + }
54.2379 + ~AutoLinkScope() {
54.2380 + if (scope_) {
54.2381 + assert(*prevp_ == this);
54.2382 + *prevp_ = prev_;
54.2383 + }
54.2384 + }
54.2385 + Scope *scope() const {
54.2386 + return scope_;
54.2387 + }
54.2388 +
54.2389 + private:
54.2390 + AutoLinkScope **prevp_;
54.2391 + AutoLinkScope *prev_;
54.2392 + Scope *scope_;
54.2393 + };
54.2394 +
54.2395 + public:
54.2396 + NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.2397 + : NameBinderBase(zone, cc, unit),
54.2398 + link_(NULL)
54.2399 + {
54.2400 + }
54.2401 +
54.2402 + void bind() {
54.2403 + // Start with the import scope, and collect all imported names.
54.2404 + AutoLinkScope importScope(&link_, unit_->importScope());
54.2405 +
54.2406 + for (size_t i = 0; i < unit_->tree()->imports()->length(); i++)
54.2407 + unit_->tree()->imports()->at(i)->accept(this);
54.2408 +
54.2409 + // Next, enter the global scope and walk all statements.
54.2410 + AutoLinkScope globalScope(&link_, unit_->globalScope());
54.2411 + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
54.2412 + Statement *stmt = unit_->tree()->statements()->at(i);
54.2413 + stmt->accept(this);
54.2414 + }
54.2415 + }
54.2416 +
54.2417 + void visitVariableDeclaration(VariableDeclaration *node) {
54.2418 + // Bind the initializer before registering the declaration, so that we
54.2419 + // can error on bogus initializers (new x = x).
54.2420 + if (node->initialization())
54.2421 + node->initialization()->accept(this);
54.2422 +
54.2423 + // If the node already has a symbol (meaning it was a global), then
54.2424 + // we don't have to do anything more.
54.2425 + if (node->sym())
54.2426 + return;
54.2427 +
54.2428 + Local<Type> type(zone_, buildVariableType(node));
54.2429 + if (!type)
54.2430 + return;
54.2431 +
54.2432 + VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type);
54.2433 + node->setSymbol(sym);
54.2434 +
54.2435 + if (Symbol *other = link_->scope()->localLookup(sym->name())) {
54.2436 + // Report, but allow errors to continue.
54.2437 + cc_.reportError(sym->pos(), Message_RedeclaredName,
54.2438 + sym->name()->chars(),
54.2439 + other->pos().line,
54.2440 + other->pos().col);
54.2441 + return;
54.2442 + }
54.2443 +
54.2444 + link_->scope()->addSymbol(sym);
54.2445 + }
54.2446 + void visitEnumStatement(EnumStatement *node) {
54.2447 + }
54.2448 + void visitFunctionStatement(FunctionStatement *node) {
54.2449 + AutoLinkScope argScope(&link_, node->argScope());
54.2450 + AutoLinkScope varScope(&link_, node->varScope());
54.2451 +
54.2452 + // If the function is in the global scope, we've already computed its
54.2453 + // type.
54.2454 + if (node->sym()->scope()->kind() != Scope::GLOBAL) {
54.2455 + Local<FunctionType> type(zone_, node->sym()->type());
54.2456 + if (!fillFunctionType(type, node->signature()))
54.2457 + return;
54.2458 + }
54.2459 +
54.2460 + if (node->body())
54.2461 + node->body()->accept(this);
54.2462 + }
54.2463 + void visitStructureStatement(StructureStatement *node) {
54.2464 + assert(false);
54.2465 + }
54.2466 + void visitFunctionTypeStatement(FunctionTypeStatement *node) {
54.2467 + assert(false);
54.2468 + }
54.2469 +
54.2470 + void visitNameProxy(NameProxy *proxy) {
54.2471 + // We could have already bound globals.
54.2472 + if (proxy->sym())
54.2473 + return;
54.2474 +
54.2475 + Scope *scope = link_->scope();
54.2476 + Symbol *sym = scope->lookup(proxy->name());
54.2477 + if (!sym)
54.2478 + cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars());
54.2479 + proxy->bind(sym);
54.2480 + }
54.2481 + void visitAssignment(Assignment *node) {
54.2482 + node->lvalue()->accept(this);
54.2483 + node->expression()->accept(this);
54.2484 + }
54.2485 + void visitBinaryExpression(BinaryExpression *node) {
54.2486 + node->left()->accept(this);
54.2487 + node->right()->accept(this);
54.2488 + }
54.2489 + void visitReturnStatement(ReturnStatement *node) {
54.2490 + node->expression()->accept(this);
54.2491 + }
54.2492 + void visitForStatement(ForStatement *node) {
54.2493 + AutoLinkScope scope(&link_, node->scope());
54.2494 +
54.2495 + if (node->initialization())
54.2496 + node->initialization()->accept(this);
54.2497 + if (node->condition())
54.2498 + node->condition()->accept(this);
54.2499 + if (node->update())
54.2500 + node->update()->accept(this);
54.2501 + node->body()->accept(this);
54.2502 + }
54.2503 + void visitBlockStatement(BlockStatement *node) {
54.2504 + AutoLinkScope scope(&link_, node->scope());
54.2505 + for (size_t i = 0; i < node->statements()->length(); i++)
54.2506 + node->statements()->at(i)->accept(this);
54.2507 + }
54.2508 + void visitIntegerLiteral(IntegerLiteral *node) {
54.2509 + }
54.2510 + void visitExpressionStatement(ExpressionStatement *node) {
54.2511 + node->expression()->accept(this);
54.2512 + }
54.2513 + void visitCallExpression(CallExpression *node) {
54.2514 + node->callee()->accept(this);
54.2515 + for (size_t i = 0; i < node->arguments()->length(); i++)
54.2516 + node->arguments()->at(i)->accept(this);
54.2517 + }
54.2518 + void visitIfStatement(IfStatement *node) {
54.2519 + node->condition()->accept(this);
54.2520 + node->ifTrue()->accept(this);
54.2521 + if (node->ifFalse())
54.2522 + node->ifFalse()->accept(this);
54.2523 + }
54.2524 + void visitIndexExpression(IndexExpression *node) {
54.2525 + node->left()->accept(this);
54.2526 + node->right()->accept(this);
54.2527 + }
54.2528 + void visitFloatLiteral(FloatLiteral *node) {
54.2529 + }
54.2530 + void visitWhileStatement(WhileStatement *node) {
54.2531 + node->condition()->accept(this);
54.2532 + node->body()->accept(this);
54.2533 + }
54.2534 + void visitBreakStatement(BreakStatement *node) {
54.2535 + }
54.2536 + void visitContinueStatement(ContinueStatement *node) {
54.2537 + }
54.2538 + void visitStringLiteral(StringLiteral *node) {
54.2539 + }
54.2540 + void visitIncDecExpression(IncDecExpression *node) {
54.2541 + node->expression()->accept(this);
54.2542 + }
54.2543 + void visitUnaryExpression(UnaryExpression *node) {
54.2544 + if (node->tag())
54.2545 + node->tag()->accept(this);
54.2546 + node->expression()->accept(this);
54.2547 + }
54.2548 + void visitTernaryExpression(TernaryExpression *node) {
54.2549 + node->condition()->accept(this);
54.2550 + node->left()->accept(this);
54.2551 + node->right()->accept(this);
54.2552 + }
54.2553 + void visitBooleanLiteral(BooleanLiteral *node) {
54.2554 + }
54.2555 + void visitFieldExpression(FieldExpression *node) {
54.2556 + node->left()->accept(this);
54.2557 + }
54.2558 + void visitSwitchStatement(SwitchStatement *node) {
54.2559 + node->expression()->accept(this);
54.2560 + node->defaultCase()->accept(this);
54.2561 + for (size_t i = 0; i < node->cases()->length(); i++) {
54.2562 + // We don't test case expressions because they are literals.
54.2563 + Case *c = node->cases()->at(i);
54.2564 + c->statement()->accept(this);
54.2565 + }
54.2566 + }
54.2567 + void visitArrayLiteral(ArrayLiteral *node) {
54.2568 + for (size_t i = 0; i < node->expressions()->length(); i++)
54.2569 + node->expressions()->at(i)->accept(this);
54.2570 + }
54.2571 + void visitImportStatement(ImportStatement *node) {
54.2572 + }
54.2573 +
54.2574 + private:
54.2575 + AutoLinkScope *link_;
54.2576 +};
54.2577 +
54.2578 +void
54.2579 +ke::BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.2580 +{
54.2581 + AutoEnterCompileContext enter(cc, unit);
54.2582 +
54.2583 + GlobalBuilder builder(zone, cc, unit);
54.2584 + Local<Struct> globals(zone, builder.build());
54.2585 + if (!globals || unit->failed())
54.2586 + return;
54.2587 +
54.2588 + unit->module()->setGlobals(globals);
54.2589 +}
54.2590 +
54.2591 +void
54.2592 +ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit)
54.2593 +{
54.2594 + AutoEnterCompileContext enter(cc, unit);
54.2595 + NameBinder binder(zone, cc, unit);
54.2596 + binder.bind();
54.2597 +}
55.1 --- a/src/compiler/NameBinding.h Mon Jun 10 00:46:29 2013 +0100
55.2 +++ b/src/compiler/NameBinding.h Mon Jun 10 01:04:43 2013 +0100
55.3 @@ -1,48 +1,48 @@
55.4 -/* vim: set ts=4 sw=4 tw=99 et:
55.5 - *
55.6 - * Copyright (C) 2012 David Anderson
55.7 - *
55.8 - * This file is part of SourcePawn.
55.9 - *
55.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
55.11 - * the terms of the GNU General Public License as published by the Free
55.12 - * Software Foundation, either version 3 of the License, or (at your option)
55.13 - * any later version.
55.14 - *
55.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
55.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
55.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
55.18 - *
55.19 - * You should have received a copy of the GNU General Public License along with
55.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
55.21 - */
55.22 -#ifndef _include_name_binding_h_
55.23 -#define _include_name_binding_h_
55.24 -
55.25 -#include "../PoolAllocator.h"
55.26 -#include "../Types.h"
55.27 -#include "Scanner.h"
55.28 -
55.29 -namespace ke {
55.30 -
55.31 -class Zone;
55.32 -class CompileContext;
55.33 -struct TranslationUnit;
55.34 -
55.35 -// Creates symbols and types for names that are global or can be derived from
55.36 -// a global. This phase also populates global scopes with lists of exported
55.37 -// symbols.
55.38 -void PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
55.39 -
55.40 -// Because of the way globals work in Pawn, we need a precursor step to
55.41 -// actually enter global symbols into the global struct. They're already in
55.42 -// the global symbol table, so we know they won't clash. This process also
55.43 -// binds any remaining types on global variables.
55.44 -void BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit);
55.45 -
55.46 -// Bind all outstanding names and finalize all unfinished types.
55.47 -void BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
55.48 -
55.49 -}
55.50 -
55.51 -#endif // _include_name_binding_h_
55.52 +/* vim: set ts=4 sw=4 tw=99 et:
55.53 + *
55.54 + * Copyright (C) 2012 David Anderson
55.55 + *
55.56 + * This file is part of SourcePawn.
55.57 + *
55.58 + * SourcePawn is free software: you can redistribute it and/or modify it under
55.59 + * the terms of the GNU General Public License as published by the Free
55.60 + * Software Foundation, either version 3 of the License, or (at your option)
55.61 + * any later version.
55.62 + *
55.63 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
55.64 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
55.65 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
55.66 + *
55.67 + * You should have received a copy of the GNU General Public License along with
55.68 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
55.69 + */
55.70 +#ifndef _include_name_binding_h_
55.71 +#define _include_name_binding_h_
55.72 +
55.73 +#include "../PoolAllocator.h"
55.74 +#include "../Types.h"
55.75 +#include "Scanner.h"
55.76 +
55.77 +namespace ke {
55.78 +
55.79 +class Zone;
55.80 +class CompileContext;
55.81 +struct TranslationUnit;
55.82 +
55.83 +// Creates symbols and types for names that are global or can be derived from
55.84 +// a global. This phase also populates global scopes with lists of exported
55.85 +// symbols.
55.86 +void PopulateNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
55.87 +
55.88 +// Because of the way globals work in Pawn, we need a precursor step to
55.89 +// actually enter global symbols into the global struct. They're already in
55.90 +// the global symbol table, so we know they won't clash. This process also
55.91 +// binds any remaining types on global variables.
55.92 +void BindGlobals(Zone *zone, CompileContext &cc, TranslationUnit *unit);
55.93 +
55.94 +// Bind all outstanding names and finalize all unfinished types.
55.95 +void BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit);
55.96 +
55.97 +}
55.98 +
55.99 +#endif // _include_name_binding_h_
56.1 --- a/src/compiler/Parser.cpp Mon Jun 10 00:46:29 2013 +0100
56.2 +++ b/src/compiler/Parser.cpp Mon Jun 10 01:04:43 2013 +0100
56.3 @@ -1,1787 +1,1787 @@
56.4 -/* vim: set ts=4 sw=4 tw=99 et:
56.5 - *
56.6 - * Copyright (C) 2012 David Anderson
56.7 - *
56.8 - * This file is part of SourcePawn.
56.9 - *
56.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
56.11 - * the terms of the GNU General Public License as published by the Free
56.12 - * Software Foundation, either version 3 of the License, or (at your option)
56.13 - * any later version.
56.14 - *
56.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
56.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
56.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
56.18 - *
56.19 - * You should have received a copy of the GNU General Public License along with
56.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
56.21 - */
56.22 -#include <string.h>
56.23 -#include "../Zone.h"
56.24 -#include "../FixedArray.h"
56.25 -#include "../Heap.h"
56.26 -#include "../Strings.h"
56.27 -#include "../TypeManager.h"
56.28 -#include "Parser.h"
56.29 -#include "../Heap-inl.h"
56.30 -
56.31 -using namespace ke;
56.32 -
56.33 -Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
56.34 - : zone_(zone),
56.35 - cc_(cc),
56.36 - pool_(zone_->pool()),
56.37 - scanner_(cc, stream, length),
56.38 - unbound_(NULL)
56.39 -{
56.40 - unbound_ = new (pool_) PoolList<NameProxy *>();
56.41 - imports_ = new (pool_) PoolList<ImportStatement *>();
56.42 -}
56.43 -
56.44 -bool
56.45 -Parser::peek(TokenKind kind)
56.46 -{
56.47 - return scanner_.peek() == kind;
56.48 -}
56.49 -
56.50 -bool
56.51 -Parser::match(TokenKind kind)
56.52 -{
56.53 - if (!peek(kind))
56.54 - return false;
56.55 - scanner_.scan();
56.56 - return true;
56.57 -}
56.58 -
56.59 -bool
56.60 -Parser::matchSemicolon()
56.61 -{
56.62 - return expect(TOK_SEMICOLON);
56.63 -}
56.64 -
56.65 -bool
56.66 -Parser::expect(TokenKind kind)
56.67 -{
56.68 - TokenKind got = scanner_.scan();
56.69 - if (got == kind)
56.70 - return true;
56.71 - cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
56.72 - return false;
56.73 -}
56.74 -
56.75 -bool
56.76 -Parser::matchName(String **name, TokenKind kind)
56.77 -{
56.78 - assert(kind == TOK_NAME || kind == TOK_LABEL);
56.79 - *name = NULL;
56.80 - if (!match(kind))
56.81 - return false;
56.82 - *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
56.83 - return true;
56.84 -}
56.85 -
56.86 -String *
56.87 -Parser::expectName()
56.88 -{
56.89 - if (!expect(TOK_NAME))
56.90 - return NULL;
56.91 - return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
56.92 -}
56.93 -
56.94 -Expression *
56.95 -Parser::primitive()
56.96 -{
56.97 - TokenKind kind = scanner_.peek();
56.98 - switch (kind) {
56.99 - case TOK_FLOAT_LITERAL:
56.100 - {
56.101 - scanner_.scan();
56.102 - double value = Scanner::ParseDouble(scanner_.literal());
56.103 - return new (pool_) FloatLiteral(scanner_.begin(), value);
56.104 - }
56.105 -
56.106 - case TOK_HEX_LITERAL:
56.107 - {
56.108 - scanner_.scan();
56.109 - int value = strtol(scanner_.literal(), NULL, 16);
56.110 - return new (pool_) IntegerLiteral(scanner_.begin(), value);
56.111 - }
56.112 -
56.113 - case TOK_INTEGER_LITERAL:
56.114 - {
56.115 - scanner_.scan();
56.116 - int value = atoi(scanner_.literal());
56.117 - return new (pool_) IntegerLiteral(scanner_.begin(), value);
56.118 - }
56.119 -
56.120 - case TOK_TRUE:
56.121 - case TOK_FALSE:
56.122 - scanner_.scan();
56.123 - return new (pool_) BooleanLiteral(scanner_.begin(), kind);
56.124 -
56.125 - case TOK_STRING_LITERAL:
56.126 - {
56.127 - scanner_.scan();
56.128 - Local<String> string(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.129 - return new (pool_) StringLiteral(scanner_.begin(), string);
56.130 - }
56.131 -
56.132 - default:
56.133 - {
56.134 - if (kind != TOK_ERROR)
56.135 - cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
56.136 - return NULL;
56.137 - }
56.138 - }
56.139 -}
56.140 -
56.141 -Expression *
56.142 -Parser::fixedArrayLiteral()
56.143 -{
56.144 - SourcePosition pos = scanner_.begin();
56.145 -
56.146 - ExpressionList *list = new (pool_) ExpressionList();
56.147 - do {
56.148 - // { } is an illegal array literal.
56.149 - if (list->length() > 0 && match(TOK_LBRACE))
56.150 - break;
56.151 -
56.152 - Expression *expr = NULL;
56.153 - if (peek(TOK_LBRACE))
56.154 - expr = fixedArrayLiteral();
56.155 - else
56.156 - expr = primitive();
56.157 - if (!expr)
56.158 - return NULL;
56.159 -
56.160 - if (!list->append(expr))
56.161 - return NULL;
56.162 -
56.163 - if (!match(TOK_COMMA)) {
56.164 - if (!expect(TOK_RBRACE))
56.165 - return NULL;
56.166 - break;
56.167 - }
56.168 - } while (true);
56.169 -
56.170 - return new (pool_) ArrayLiteral(pos, TOK_LBRACE, list);
56.171 -}
56.172 -
56.173 -Expression *
56.174 -Parser::prefix()
56.175 -{
56.176 - switch (scanner_.peek()) {
56.177 - case TOK_LPAREN:
56.178 - {
56.179 - scanner_.scan();
56.180 - Expression *expr = expression();
56.181 - if (!expr)
56.182 - return NULL;
56.183 - if (!expect(TOK_RPAREN))
56.184 - return NULL;
56.185 - return expr;
56.186 - }
56.187 -
56.188 - case TOK_NAME:
56.189 - {
56.190 - Local<String> name(zone_, expectName());
56.191 - if (!name)
56.192 - return NULL;
56.193 - return new (pool_) NameProxy(scanner_.begin(), name);
56.194 - }
56.195 -
56.196 - default:
56.197 - return primitive();
56.198 - }
56.199 -}
56.200 -
56.201 -// Parses only old-style declarations.
56.202 -bool
56.203 -Parser::typeAndName(Expression **type, String **namep)
56.204 -{
56.205 - if (match(TOK_LABEL)) {
56.206 - // Old-style declaration:
56.207 - // new X:type
56.208 - Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.209 - if (!name)
56.210 - return false;
56.211 -
56.212 - *type = new (pool_) NameProxy(scanner_.begin(), name);
56.213 - *namep = expectName();
56.214 - return !!*namep;
56.215 - }
56.216 -
56.217 - *type = NULL;
56.218 - *namep = expectName();
56.219 -
56.220 - return !!*namep;
56.221 -}
56.222 -
56.223 -// Parses both old and new style declarations.
56.224 -bool
56.225 -Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind)
56.226 -{
56.227 - // decl ::= newdecl | olddecl
56.228 - // newdecl ::= Type Ident
56.229 - // olddecl ::= Label? (Ident | "...")
56.230 - // type ::= Ident
56.231 - // label ::= Ident ":"
56.232 - //
56.233 - if (match(TOK_LABEL)) {
56.234 - // We something of the form:
56.235 - // Label Ident
56.236 - // or: Label "..."
56.237 - Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.238 - if (!name)
56.239 - return false;
56.240 -
56.241 - *type = new (pool_) NameProxy(scanner_.begin(), name);
56.242 - if (kind == DeclArg && match(TOK_ELLIPSES)) {
56.243 - *namep = NULL;
56.244 - } else {
56.245 - if ((*namep = expectName()) == NULL)
56.246 - return false;
56.247 - }
56.248 - return true;
56.249 - }
56.250 -
56.251 - Local<String> name(zone_, expectName());
56.252 - if (!name)
56.253 - return false;
56.254 -
56.255 - if (peek(TOK_NAME) || (kind == DeclArg && peek(TOK_ELLIPSES))) {
56.256 - // We got something of the form:
56.257 - // Ident Ident
56.258 - *type = new (pool_) NameProxy(scanner_.begin(), name);
56.259 - if (peek(TOK_NAME)) {
56.260 - if ((*namep = expectName()) == NULL)
56.261 - return false;
56.262 - } else {
56.263 - *namep = NULL;
56.264 - }
56.265 - return true;
56.266 - }
56.267 -
56.268 - // We got something of the form:
56.269 - // Ident
56.270 - *type = NULL;
56.271 - *namep = name;
56.272 - return true;
56.273 -}
56.274 -
56.275 -Expression *
56.276 -Parser::call(Expression *callee)
56.277 -{
56.278 - ExpressionList *arguments = new (pool_) ExpressionList();
56.279 -
56.280 - SourcePosition pos = scanner_.begin();
56.281 - expect(TOK_LPAREN);
56.282 -
56.283 - if (!match(TOK_RPAREN)) {
56.284 - while (true) {
56.285 - Expression *expr = expression();
56.286 - if (!expr)
56.287 - return NULL;
56.288 -
56.289 - if (!arguments->append(expr))
56.290 - return NULL;
56.291 -
56.292 - if (!match(TOK_COMMA))
56.293 - break;
56.294 - }
56.295 -
56.296 - if (!expect(TOK_RPAREN))
56.297 - return NULL;
56.298 - }
56.299 -
56.300 - return new (pool_) CallExpression(pos, callee, arguments);
56.301 -}
56.302 -
56.303 -Expression *
56.304 -Parser::index(Expression *left)
56.305 -{
56.306 - expect(TOK_LBRACKET);
56.307 -
56.308 - SourcePosition pos = scanner_.begin();
56.309 - Expression *expr = expression();
56.310 - if (!expr)
56.311 - return NULL;
56.312 -
56.313 - if (!expect(TOK_RBRACKET))
56.314 - return NULL;
56.315 -
56.316 - return new (pool_) IndexExpression(pos, left, expr);
56.317 -}
56.318 -
56.319 -Expression *
56.320 -Parser::field(Expression *left)
56.321 -{
56.322 - expect(TOK_DOT);
56.323 -
56.324 - SourcePosition pos = scanner_.begin();
56.325 - Local<String> name(zone_, expectName());
56.326 - if (!name)
56.327 - return NULL;
56.328 -
56.329 - return new (pool_) FieldExpression(pos, left, name);
56.330 -}
56.331 -
56.332 -Expression *
56.333 -Parser::primary()
56.334 -{
56.335 - Expression *expr = prefix();
56.336 - if (!expr)
56.337 - return NULL;
56.338 -
56.339 - for (;;) {
56.340 - switch (scanner_.peek()) {
56.341 - case TOK_LPAREN:
56.342 - if ((expr = call(expr)) == NULL)
56.343 - return NULL;
56.344 - break;
56.345 -
56.346 - case TOK_LBRACKET:
56.347 - if ((expr = index(expr)) == NULL)
56.348 - return NULL;
56.349 - break;
56.350 -
56.351 - case TOK_DOT:
56.352 - if ((expr = field(expr)) == NULL)
56.353 - return NULL;
56.354 - break;
56.355 -
56.356 - default:
56.357 - return expr;
56.358 - }
56.359 - }
56.360 -}
56.361 -
56.362 -Expression *
56.363 -Parser::unary()
56.364 -{
56.365 - TokenKind token = scanner_.peek();
56.366 -
56.367 - SourcePosition pos = scanner_.begin();
56.368 - switch (token) {
56.369 - case TOK_INCREMENT:
56.370 - case TOK_DECREMENT:
56.371 - {
56.372 - scanner_.scan();
56.373 - Expression *expr = unary();
56.374 - if (!expr)
56.375 - return NULL;
56.376 - return new (pool_) IncDecExpression(pos, token, expr, false);
56.377 - }
56.378 -
56.379 - case TOK_MINUS:
56.380 - case TOK_NOT:
56.381 - case TOK_TILDE:
56.382 - {
56.383 - scanner_.scan();
56.384 - Expression *expr = unary();
56.385 - if (!expr)
56.386 - return NULL;
56.387 - return new (pool_) UnaryExpression(pos, token, expr);
56.388 - }
56.389 -
56.390 - case TOK_SIZEOF:
56.391 - {
56.392 - scanner_.scan();
56.393 - if (!expect(TOK_LPAREN))
56.394 - return NULL;
56.395 - Expression *expr = unary();
56.396 - if (!expr)
56.397 - return NULL;
56.398 - if (!expect(TOK_RPAREN))
56.399 - return NULL;
56.400 - return new (pool_) UnaryExpression(pos, token, expr);
56.401 - }
56.402 -
56.403 - case TOK_LABEL:
56.404 - {
56.405 - scanner_.scan();
56.406 - Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.407 - if (!tag)
56.408 - return NULL;
56.409 -
56.410 - NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), tag);
56.411 -
56.412 - Expression *expr = unary();
56.413 - if (!expr)
56.414 - return NULL;
56.415 -
56.416 - return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, proxy);
56.417 - }
56.418 -
56.419 - default:
56.420 - break;
56.421 - }
56.422 -
56.423 - Expression *expr = primary();
56.424 -
56.425 - token = scanner_.peek();
56.426 - if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
56.427 - scanner_.scan();
56.428 - return new (pool_) IncDecExpression(pos, token, expr, true);
56.429 - }
56.430 -
56.431 - return expr;
56.432 -}
56.433 -
56.434 -Expression *
56.435 -Parser::multiplication()
56.436 -{
56.437 - Expression *left = unary();
56.438 - do {
56.439 - if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
56.440 - break;
56.441 - SourcePosition pos = scanner_.begin();
56.442 - TokenKind kind = scanner_.last();
56.443 - Expression *right = unary();
56.444 - if (!right)
56.445 - return NULL;
56.446 - left = new (pool_) BinaryExpression(pos, kind, left, right);
56.447 - } while (left);
56.448 - return left;
56.449 -}
56.450 -
56.451 -Expression *
56.452 -Parser::addition()
56.453 -{
56.454 - Expression *left = multiplication();
56.455 - while (left) {
56.456 - if (!match(TOK_PLUS) && !match(TOK_MINUS))
56.457 - break;
56.458 - SourcePosition pos = scanner_.begin();
56.459 - TokenKind kind = scanner_.last();
56.460 - Expression *right = multiplication();
56.461 - if (!right)
56.462 - return NULL;
56.463 - left = new (pool_) BinaryExpression(pos, kind, left, right);
56.464 - }
56.465 - return left;
56.466 -}
56.467 -
56.468 -Expression *
56.469 -Parser::shift()
56.470 -{
56.471 - Expression *left = addition();
56.472 - while (left) {
56.473 - if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
56.474 - break;
56.475 - SourcePosition pos = scanner_.begin();
56.476 - TokenKind kind = scanner_.last();
56.477 - Expression *right = addition();
56.478 - if (!right)
56.479 - return NULL;
56.480 - left = new (pool_) BinaryExpression(pos, kind, left, right);
56.481 - }
56.482 - return left;
56.483 -}
56.484 -
56.485 -Expression *
56.486 -Parser::bitand_()
56.487 -{
56.488 - Expression *left = shift();
56.489 - while (left) {
56.490 - if (!match(TOK_BITAND))
56.491 - break;
56.492 - SourcePosition pos = scanner_.begin();
56.493 - Expression *right = shift();
56.494 - if (!right)
56.495 - return NULL;
56.496 - left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
56.497 - }
56.498 - return left;
56.499 -}
56.500 -
56.501 -Expression *
56.502 -Parser::bitxor()
56.503 -{
56.504 - Expression *left = bitand_();
56.505 - while (left) {
56.506 - if (!match(TOK_BITXOR))
56.507 - break;
56.508 - SourcePosition pos = scanner_.begin();
56.509 - Expression *right = shift();
56.510 - if (!right)
56.511 - return NULL;
56.512 - left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
56.513 - }
56.514 - return left;
56.515 -}
56.516 -
56.517 -Expression *
56.518 -Parser::bitor_()
56.519 -{
56.520 - Expression *left = bitxor();
56.521 - while (left) {
56.522 - if (!match(TOK_BITOR))
56.523 - break;
56.524 - SourcePosition pos = scanner_.begin();
56.525 - Expression *right = bitxor();
56.526 - if (!right)
56.527 - return NULL;
56.528 - left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
56.529 - }
56.530 - return left;
56.531 -}
56.532 -
56.533 -Expression *
56.534 -Parser::relational()
56.535 -{
56.536 - Expression *left = bitor_();
56.537 - while (left) {
56.538 - TokenKind kind = scanner_.peek();
56.539 - if (kind < TOK_LT || kind > TOK_GE)
56.540 - break;
56.541 - scanner_.scan();
56.542 - SourcePosition pos = scanner_.begin();
56.543 - Expression *right = shift();
56.544 - if (!right)
56.545 - return NULL;
56.546 - left = new (pool_) BinaryExpression(pos, kind, left, right);
56.547 - }
56.548 - return left;
56.549 -}
56.550 -
56.551 -Expression *
56.552 -Parser::equals()
56.553 -{
56.554 - Expression *left = relational();
56.555 - while (left) {
56.556 - if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
56.557 - break;
56.558 - TokenKind kind = scanner_.last();
56.559 - SourcePosition pos = scanner_.begin();
56.560 - Expression *right = relational();
56.561 - if (!right)
56.562 - return NULL;
56.563 - left = new (pool_) BinaryExpression(pos, kind, left, right);
56.564 - }
56.565 - return left;
56.566 -}
56.567 -
56.568 -Expression *
56.569 -Parser::and_()
56.570 -{
56.571 - Expression *left = equals();
56.572 - while (left) {
56.573 - if (!match(TOK_AND))
56.574 - break;
56.575 - SourcePosition pos = scanner_.begin();
56.576 - Expression *right = equals();
56.577 - if (!right)
56.578 - return NULL;
56.579 - left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
56.580 - }
56.581 - return left;
56.582 -}
56.583 -
56.584 -Expression *
56.585 -Parser::or_()
56.586 -{
56.587 - Expression *left = and_();
56.588 - while (left) {
56.589 - if (!match(TOK_OR))
56.590 - break;
56.591 - SourcePosition pos = scanner_.begin();
56.592 - Expression *right = and_();
56.593 - if (!right)
56.594 - return NULL;
56.595 - left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
56.596 - }
56.597 - return left;
56.598 -}
56.599 -
56.600 -Expression *
56.601 -Parser::ternary()
56.602 -{
56.603 - Expression *cond = or_();
56.604 - if (!cond)
56.605 - return NULL;
56.606 -
56.607 - if (!match(TOK_QMARK))
56.608 - return cond;
56.609 -
56.610 - Expression *left;
56.611 - SourcePosition pos = scanner_.begin();
56.612 - AutoAllowTags<false> disableTags(scanner_);
56.613 - {
56.614 - if ((left = expression()) == NULL)
56.615 - return NULL;
56.616 - }
56.617 -
56.618 - if (!expect(TOK_COLON))
56.619 - return NULL;
56.620 -
56.621 - Expression *right = expression();
56.622 - if (!right)
56.623 - return NULL;
56.624 -
56.625 - return new (pool_) TernaryExpression(pos, cond, left, right);
56.626 -}
56.627 -
56.628 -Expression *
56.629 -Parser::assignment()
56.630 -{
56.631 - Expression *left = ternary();
56.632 - while (left) {
56.633 - TokenKind token = scanner_.peek();
56.634 - if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
56.635 - break;
56.636 - scanner_.scan();
56.637 - SourcePosition pos = scanner_.begin();
56.638 - Expression *expr = ternary();
56.639 - if (!expr)
56.640 - return NULL;
56.641 -
56.642 - left = new (pool_) Assignment(pos, token, left, expr);
56.643 - }
56.644 - return left;
56.645 -}
56.646 -
56.647 -Expression *
56.648 -Parser::expression()
56.649 -{
56.650 - return assignment();
56.651 -}
56.652 -
56.653 -Statement *
56.654 -Parser::while_()
56.655 -{
56.656 - // while ::= "while" "(" expr ")" statement
56.657 - SourcePosition pos = scanner_.begin();
56.658 - scanner_.scan();
56.659 -
56.660 - if (!expect(TOK_LPAREN))
56.661 - return NULL;
56.662 -
56.663 - Expression *condition = expression();
56.664 - if (!condition)
56.665 - return NULL;
56.666 -
56.667 - if (!expect(TOK_RPAREN))
56.668 - return NULL;
56.669 -
56.670 - Statement *body;
56.671 - if (scanner_.peek() == TOK_LBRACE)
56.672 - body = block();
56.673 - else
56.674 - body = localStatement();
56.675 - if (!body)
56.676 - return NULL;
56.677 -
56.678 - return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
56.679 -}
56.680 -
56.681 -Statement *
56.682 -Parser::do_()
56.683 -{
56.684 - // do ::= "do" block "while" "(" expr ")"
56.685 - SourcePosition pos = scanner_.begin();
56.686 - scanner_.scan();
56.687 -
56.688 - Statement *body = block();
56.689 - if (!body)
56.690 - return NULL;
56.691 -
56.692 - if (!expect(TOK_WHILE))
56.693 - return NULL;
56.694 -
56.695 - if (!expect(TOK_LPAREN))
56.696 - return NULL;
56.697 - Expression *condition = expression();
56.698 - if (!condition)
56.699 - return NULL;
56.700 - if (!expect(TOK_RPAREN))
56.701 - return NULL;
56.702 -
56.703 - return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
56.704 -}
56.705 -
56.706 -Statement *
56.707 -Parser::switch_()
56.708 -{
56.709 - // switch ::= "switch" "(" expr ")" "{" case* defaultcase? "}"
56.710 - // case ::= "case" casevals ":" statement
56.711 - // defaultcase ::= "default" ":" statement
56.712 - //
56.713 - expect(TOK_SWITCH);
56.714 -
56.715 - SourcePosition pos = scanner_.begin();
56.716 -
56.717 - if (!expect(TOK_LPAREN))
56.718 - return NULL;
56.719 - Expression *expr = expression();
56.720 - if (!expr)
56.721 - return NULL;
56.722 - if (!expect(TOK_RPAREN))
56.723 - return NULL;
56.724 -
56.725 - if (!expect(TOK_LBRACE))
56.726 - return NULL;
56.727 -
56.728 - SourcePosition defaultPos;
56.729 - PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
56.730 -
56.731 - Statement *defaultCase = NULL;
56.732 -
56.733 - while (!peek(TOK_RBRACE)) {
56.734 - Expression *expr = NULL;
56.735 - ExpressionList *others = NULL;
56.736 - if (match(TOK_DEFAULT)) {
56.737 - if (defaultCase) {
56.738 - cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
56.739 - return NULL;
56.740 - }
56.741 -
56.742 - defaultPos = scanner_.begin();
56.743 - } else {
56.744 - if (defaultCase) {
56.745 - cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
56.746 - return NULL;
56.747 - }
56.748 -
56.749 - if (!expect(TOK_CASE))
56.750 - return NULL;
56.751 -
56.752 - // A limitation in the grammar is that |case <NAME>:| will be
56.753 - // detected as a label.
56.754 - AutoAllowTags<false> disableTags(scanner_);
56.755 -
56.756 - if ((expr = expression()) == NULL)
56.757 - return NULL;
56.758 -
56.759 - if (peek(TOK_COMMA)) {
56.760 - others = new (pool_) ExpressionList();
56.761 - while (match(TOK_COMMA)) {
56.762 - Expression *other = expression();
56.763 - if (!other)
56.764 - return NULL;
56.765 - if (!others->append(other))
56.766 - return NULL;
56.767 - }
56.768 - }
56.769 - }
56.770 -
56.771 - if (!expect(TOK_COLON))
56.772 - return NULL;
56.773 -
56.774 - Statement *statement = localStatement();
56.775 - if (!statement)
56.776 - return NULL;
56.777 -
56.778 - if (!peek(TOK_CASE) &&
56.779 - !peek(TOK_DEFAULT) &&
56.780 - !peek(TOK_RBRACE))
56.781 - {
56.782 - cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
56.783 - return NULL;
56.784 - }
56.785 -
56.786 - if (expr) {
56.787 - Case *caze = new (pool_) Case(expr, others, statement);
56.788 - if (!cases->append(caze))
56.789 - return NULL;
56.790 - } else {
56.791 - defaultCase = statement;
56.792 - }
56.793 - }
56.794 -
56.795 - if (!expect(TOK_RBRACE))
56.796 - return NULL;
56.797 -
56.798 - return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
56.799 -}
56.800 -
56.801 -Statement *
56.802 -Parser::forStatement()
56.803 -{
56.804 - // for ::= "for" "(" forinit? ";" forcond? ";" forstep ")" statement
56.805 - // forint ::= "new" vardecl |
56.806 - // exprstmt
56.807 - // forcond ::= expr
56.808 - // forstep ::= exprstmt
56.809 - //
56.810 - SourcePosition pos = scanner_.begin();
56.811 - scanner_.scan();
56.812 - if (!expect(TOK_LPAREN))
56.813 - return NULL;
56.814 -
56.815 - Statement *decl = NULL;
56.816 - if (!match(TOK_SEMICOLON)) {
56.817 - if (match(TOK_NEW)) {
56.818 - if ((decl = vars(TypeQual_None)) == NULL)
56.819 - return NULL;
56.820 - } else {
56.821 - if ((decl = expressionStatement()) == NULL)
56.822 - return NULL;
56.823 - }
56.824 - if (!expect(TOK_SEMICOLON))
56.825 - return NULL;
56.826 - }
56.827 -
56.828 - Expression *condition = NULL;
56.829 - if (!match(TOK_SEMICOLON)) {
56.830 - if ((condition = expression()) == NULL)
56.831 - return NULL;
56.832 - if (!expect(TOK_SEMICOLON))
56.833 - return NULL;
56.834 - }
56.835 -
56.836 - Statement *update = NULL;
56.837 - if (!match(TOK_RPAREN)) {
56.838 - if ((update = expressionStatement()) == NULL)
56.839 - return NULL;
56.840 - if (!expect(TOK_RPAREN))
56.841 - return NULL;
56.842 - }
56.843 -
56.844 - Statement *body;
56.845 - if (scanner_.peek() == TOK_LBRACE)
56.846 - body = block();
56.847 - else
56.848 - body = localStatement();
56.849 - if (!body)
56.850 - return NULL;
56.851 -
56.852 - return new (pool_) ForStatement(pos, decl, condition, update, body);
56.853 -}
56.854 -
56.855 -ExpressionList *
56.856 -Parser::dimensions()
56.857 -{
56.858 - // dimensions ::= ("[" expr? "]")*
56.859 -
56.860 - ExpressionList *postDimensions = new (pool_) ExpressionList();
56.861 - while (match(TOK_LBRACKET)) {
56.862 - Expression *dim = NULL;
56.863 - if (!match(TOK_RBRACKET)) {
56.864 - if ((dim = expression()) == NULL)
56.865 - return NULL;
56.866 - if (!expect(TOK_RBRACKET))
56.867 - return NULL;
56.868 - }
56.869 -
56.870 - if (!postDimensions->append(dim))
56.871 - return NULL;
56.872 - }
56.873 - return postDimensions;
56.874 -}
56.875 -
56.876 -VariableDeclaration *
56.877 -Parser::var(TypeQualifiers qual)
56.878 -{
56.879 - // vardecl ::= decl ("=" expr)?
56.880 -
56.881 - Expression *type;
56.882 - Local<String> name(zone_);
56.883 -
56.884 - if (!typeAndName(&type, name.ref()))
56.885 - return NULL;
56.886 -
56.887 - ExpressionList *dims = NULL;
56.888 - if (peek(TOK_LBRACKET)) {
56.889 - if ((dims = dimensions()) == NULL)
56.890 - return NULL;;
56.891 - }
56.892 -
56.893 - SourcePosition pos = scanner_.begin();
56.894 -
56.895 - Expression *expr = NULL;
56.896 - if (match(TOK_ASSIGN)) {
56.897 - switch (scanner_.peek()) {
56.898 - // Note: we don't support [] literals yet.
56.899 - case TOK_LBRACE:
56.900 - scanner_.scan();
56.901 - if ((expr = fixedArrayLiteral()) == NULL)
56.902 - return NULL;
56.903 - break;
56.904 -
56.905 - default:
56.906 - if ((expr = expression()) == NULL)
56.907 - return NULL;
56.908 - break;
56.909 - }
56.910 - }
56.911 -
56.912 - return new (pool_) VariableDeclaration(pos, qual, name, type, dims, expr);
56.913 -}
56.914 -
56.915 -Statement *
56.916 -Parser::vars(TypeQualifiers qual)
56.917 -{
56.918 - // localvars ::= ("new" | "const" | "decl") vardecl ("," vardecl)*
56.919 - // globalvars ::= ("public" | "const" | "new" | "public" "const") vardecl
56.920 - VariableDeclaration *decl = var(qual);
56.921 - if (!decl)
56.922 - return NULL;
56.923 -
56.924 - if (!peek(TOK_COMMA))
56.925 - return decl;
56.926 -
56.927 - StatementList *statements = new (pool_) StatementList();
56.928 - if (!statements->append(decl))
56.929 - return NULL;
56.930 -
56.931 - while (match(TOK_COMMA)) {
56.932 - Statement *decl = var(qual);
56.933 - if (!decl)
56.934 - return NULL;
56.935 - if (!statements->append(decl))
56.936 - return NULL;
56.937 - }
56.938 -
56.939 - // Create a fake-o block with no scope to create a statement list.
56.940 - return new (pool_) BlockStatement(decl->pos(), statements, TOK_NEW);
56.941 -}
56.942 -
56.943 -Statement *
56.944 -Parser::returnStatement()
56.945 -{
56.946 - // return ::= "return" term |
56.947 - // "return" "expr"
56.948 -
56.949 - SourcePosition pos = scanner_.begin();
56.950 - if (!expect(TOK_RETURN))
56.951 - return NULL;
56.952 -
56.953 - Expression *expr = NULL;
56.954 - if (scanner_.peek() != TOK_SEMICOLON) {
56.955 - if ((expr = expression()) == NULL)
56.956 - return NULL;
56.957 -
56.958 - // We only care about non-void returns when determining whether a
56.959 - // tagless function is non-void.
56.960 - encounteredReturn_ = true;
56.961 - }
56.962 -
56.963 - return new (pool_) ReturnStatement(pos, expr);
56.964 -}
56.965 -
56.966 -Statement *
56.967 -Parser::expressionStatement()
56.968 -{
56.969 - // exprstmt ::= expr
56.970 - Expression *left = assignment();
56.971 - if (!left)
56.972 - return NULL;
56.973 -
56.974 - return new (pool_) ExpressionStatement(left);
56.975 -}
56.976 -
56.977 -Statement *
56.978 -Parser::block()
56.979 -{
56.980 - // block ::= "{" statement* "}"
56.981 -
56.982 - if (!expect(TOK_LBRACE))
56.983 - return NULL;
56.984 -
56.985 - SourcePosition pos = scanner_.begin();
56.986 -
56.987 - StatementList *statements = new (pool_) StatementList();
56.988 - while (!match(TOK_RBRACE)) {
56.989 - Statement *statement = localStatement();
56.990 - if (statement == NULL)
56.991 - return NULL;
56.992 - if (!statements->append(statement))
56.993 - return NULL;
56.994 - }
56.995 -
56.996 - BlockStatement *block = new (pool_) BlockStatement(pos, statements, TOK_LBRACE);
56.997 - return block;
56.998 -}
56.999 -
56.1000 -Statement *
56.1001 -Parser::if_()
56.1002 -{
56.1003 - // if ::= "if" "(" expr ")" statement elseif* else?
56.1004 - // elseif ::= "elseif" "(" expr ")" statement
56.1005 - // else ::= "else" statement
56.1006 - expect(TOK_IF);
56.1007 -
56.1008 - SourcePosition pos = scanner_.begin();
56.1009 - if (!expect(TOK_LPAREN))
56.1010 - return NULL;
56.1011 -
56.1012 - Expression *cond = expression();
56.1013 - if (!cond)
56.1014 - return NULL;
56.1015 -
56.1016 - if (!expect(TOK_RPAREN))
56.1017 - return NULL;
56.1018 -
56.1019 - Statement *ifTrue = localStatement();
56.1020 - if (!ifTrue)
56.1021 - return NULL;
56.1022 -
56.1023 - IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
56.1024 -
56.1025 - IfStatement *last = outer;
56.1026 - while (match(TOK_ELSE)) {
56.1027 - if (!match(TOK_IF)) {
56.1028 - Statement *ifFalse = localStatement();
56.1029 - if (!ifFalse)
56.1030 - return NULL;
56.1031 -
56.1032 - last->setIfFalse(ifFalse);
56.1033 - break;
56.1034 - }
56.1035 -
56.1036 - SourcePosition pos = scanner_.begin();
56.1037 - if (!expect(TOK_LPAREN))
56.1038 - return NULL;
56.1039 -
56.1040 - Expression *otherCond = expression();
56.1041 - if (!otherCond)
56.1042 - return NULL;
56.1043 -
56.1044 - if (!expect(TOK_RPAREN))
56.1045 - return NULL;
56.1046 -
56.1047 - Statement *otherIfTrue = localStatement();
56.1048 - if (!otherIfTrue)
56.1049 - return NULL;
56.1050 -
56.1051 - IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
56.1052 - last->setIfFalse(inner);
56.1053 - last = inner;
56.1054 - }
56.1055 -
56.1056 - return outer;
56.1057 -}
56.1058 -
56.1059 -Statement *
56.1060 -Parser::localStatement()
56.1061 -{
56.1062 - // statement ::= stmt term
56.1063 - // stmt ::= do | for | if | while | struct | enum |
56.1064 - // localvars | return | switch | break | continue
56.1065 -
56.1066 - Statement *statement = NULL;
56.1067 -
56.1068 - // Statements which must be followed by a semicolon will break out of the
56.1069 - // switch. If they may end in BlockStatements, they'll immediately return.
56.1070 -
56.1071 - TokenKind kind = scanner_.peek();
56.1072 - switch (kind) {
56.1073 - case TOK_CONST:
56.1074 - case TOK_NEW:
56.1075 - {
56.1076 - TypeQualifiers quals = (kind == TOK_CONST)
56.1077 - ? TypeQual_Const
56.1078 - : TypeQual_None;
56.1079 - scanner_.scan();
56.1080 - if ((statement = vars(quals)) == NULL)
56.1081 - return NULL;
56.1082 - break;
56.1083 - }
56.1084 -
56.1085 - case TOK_FOR:
56.1086 - return forStatement();
56.1087 -
56.1088 - case TOK_WHILE:
56.1089 - return while_();
56.1090 -
56.1091 - case TOK_BREAK:
56.1092 - scanner_.scan();
56.1093 - statement = new (pool_) BreakStatement(scanner_.begin());
56.1094 - break;
56.1095 -
56.1096 - case TOK_CONTINUE:
56.1097 - scanner_.scan();
56.1098 - statement = new (pool_) ContinueStatement(scanner_.begin());
56.1099 - break;
56.1100 -
56.1101 - case TOK_DO:
56.1102 - if ((statement = do_()) == NULL)
56.1103 - return NULL;
56.1104 - break;
56.1105 -
56.1106 - case TOK_RETURN:
56.1107 - if ((statement = returnStatement()) == NULL)
56.1108 - return NULL;
56.1109 - break;
56.1110 -
56.1111 - case TOK_ENUM:
56.1112 - if ((statement = enum_(TOK_NONE)) == NULL)
56.1113 - return NULL;
56.1114 - break;
56.1115 -
56.1116 - case TOK_STRUCT:
56.1117 - if ((statement = struct_()) == NULL)
56.1118 - return NULL;
56.1119 - break;
56.1120 -
56.1121 - case TOK_SWITCH:
56.1122 - return switch_();
56.1123 -
56.1124 - case TOK_IF:
56.1125 - return if_();
56.1126 -
56.1127 - case TOK_LBRACE:
56.1128 - return block();
56.1129 -
56.1130 - default:
56.1131 - break;
56.1132 - }
56.1133 -
56.1134 - if (!statement) {
56.1135 - if ((statement = expressionStatement()) == NULL)
56.1136 - return NULL;
56.1137 - }
56.1138 -
56.1139 - if (!expect(TOK_SEMICOLON))
56.1140 - return NULL;
56.1141 -
56.1142 - return statement;
56.1143 -}
56.1144 -
56.1145 -Statement *
56.1146 -Parser::struct_()
56.1147 -{
56.1148 - // struct ::= "struct" name { struct_fields }
56.1149 - // struct_fields ::= struct_field |
56.1150 - // struct_field struct_fields
56.1151 - // struct_field ::= label? name term
56.1152 - expect(TOK_STRUCT);
56.1153 -
56.1154 - Local<String> name(zone_, expectName());
56.1155 - if (!name)
56.1156 - return NULL;
56.1157 -
56.1158 - SourcePosition pos = scanner_.begin();
56.1159 -
56.1160 - if (!expect(TOK_LBRACE))
56.1161 - return NULL;
56.1162 -
56.1163 - FieldList *fields = new (pool_) FieldList();
56.1164 -
56.1165 - while (!peek(TOK_RBRACE)) {
56.1166 - Expression *type;
56.1167 - Local<String> fieldName(zone_);
56.1168 -
56.1169 - if (!fullTypeAndName(&type, fieldName.ref(), DeclField))
56.1170 - return NULL;
56.1171 -
56.1172 - SourcePosition pos = scanner_.begin();
56.1173 -
56.1174 - if (!matchSemicolon())
56.1175 - return NULL;
56.1176 -
56.1177 - StructureStatement::Field *field =
56.1178 - new (pool_) StructureStatement::Field(pos, type, fieldName);
56.1179 - if (!field || !fields->append(field))
56.1180 - return NULL;
56.1181 - }
56.1182 -
56.1183 - if (!expect(TOK_RBRACE))
56.1184 - return NULL;
56.1185 -
56.1186 - if (fields->empty()) {
56.1187 - cc_.reportError(pos, Message_StructCantBeEmpty);
56.1188 - return NULL;
56.1189 - }
56.1190 -
56.1191 - return new (pool_) StructureStatement(pos, name, fields);
56.1192 -}
56.1193 -
56.1194 -Statement *
56.1195 -Parser::enum_(TokenKind kind)
56.1196 -{
56.1197 - // enum ::= "enum" name? { enum_members? }
56.1198 - // enum_members ::= enum_member ","? |
56.1199 - // enum_member "," enum_members
56.1200 - // enum_member ::= ident ("=" constexpr)?
56.1201 - expect(TOK_ENUM);
56.1202 -
56.1203 - SourcePosition pos = scanner_.begin();
56.1204 -
56.1205 - Local<String> name(zone_);
56.1206 - if (matchName(name.ref()) && !name)
56.1207 - return NULL;
56.1208 -
56.1209 - EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
56.1210 -
56.1211 - if (!expect(TOK_LBRACE))
56.1212 - return NULL;
56.1213 -
56.1214 - do {
56.1215 - if (scanner_.peek() == TOK_RBRACE)
56.1216 - break;
56.1217 -
56.1218 - SourcePosition pos = scanner_.begin();
56.1219 - Local<String> name(zone_, expectName());
56.1220 - if (!name)
56.1221 - return NULL;
56.1222 -
56.1223 - Expression *expr = NULL;
56.1224 - if (match(TOK_ASSIGN)) {
56.1225 - if ((expr = expression()) == NULL)
56.1226 - return NULL;
56.1227 - }
56.1228 -
56.1229 - if (!entries->append(EnumStatement::Entry(name, expr, pos)))
56.1230 - return NULL;
56.1231 - } while (match(TOK_COMMA));
56.1232 - if (!expect(TOK_RBRACE))
56.1233 - return NULL;
56.1234 -
56.1235 - return new (pool_) EnumStatement(pos, kind, name, entries);
56.1236 -}
56.1237 -
56.1238 -template <class T>
56.1239 -static inline ScopedRoot<T> *
56.1240 -NewScopedRoot(PoolAllocator &pool, Handle<T> obj)
56.1241 -{
56.1242 - return new (pool) ScopedRoot<T>(obj);
56.1243 -}
56.1244 -
56.1245 -ImportStatement *
56.1246 -Parser::import(TokenKind kind)
56.1247 -{
56.1248 - SourcePosition pos = scanner_.begin();
56.1249 -
56.1250 - // import ::= "from" import_path "import" import_names
56.1251 - // | "import" import_path
56.1252 - // | "import" import_path ".*"
56.1253 - // import_path ::= name
56.1254 - // | name "." import_path
56.1255 - // import_names ::= "*"
56.1256 - // | import_name_list
56.1257 - // import_name_list ::= name
56.1258 - // | name "," import_name_list
56.1259 -
56.1260 - Local<String> name(zone_, expectName());
56.1261 - if (!name)
56.1262 - return NULL;
56.1263 -
56.1264 - PathComponent *root = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
56.1265 - PathComponent *current = root;
56.1266 -
56.1267 - // NULL namelist means that we do not import any names. An empty namelist
56.1268 - // means we import all names.
56.1269 - NameList *names = NULL;
56.1270 -
56.1271 - while (match(TOK_DOT)) {
56.1272 - if (kind == TOK_IMPORT && match(TOK_STAR)) {
56.1273 - names = new (pool_) NameList();
56.1274 - break;
56.1275 - }
56.1276 -
56.1277 - if ((name = expectName()) == NULL)
56.1278 - return NULL;
56.1279 -
56.1280 - current->next = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
56.1281 - current = current->next;
56.1282 - }
56.1283 -
56.1284 - if (kind == TOK_FROM) {
56.1285 - if (!expect(TOK_IMPORT))
56.1286 - return NULL;
56.1287 -
56.1288 - names = new (pool_) NameList();
56.1289 -
56.1290 - if (!match(TOK_STAR)) {
56.1291 - if (!matchName(name.address())) {
56.1292 - cc_.reportError(scanner_.begin(), Message_BadImportFrom);
56.1293 - return NULL;
56.1294 - }
56.1295 -
56.1296 - if (!name || !names->append(NewScopedRoot<String>(pool_, name)))
56.1297 - return NULL;
56.1298 -
56.1299 - while (match(TOK_COMMA)) {
56.1300 - if ((name = expectName()) == NULL)
56.1301 - return NULL;
56.1302 - if (!names->append(NewScopedRoot<String>(pool_, name)))
56.1303 - return NULL;
56.1304 - }
56.1305 - }
56.1306 - }
56.1307 -
56.1308 - return new (pool_) ImportStatement(pos, root, names);
56.1309 -}
56.1310 -
56.1311 -Statement *
56.1312 -Parser::function(TokenKind token)
56.1313 -{
56.1314 - Expression *returnType;
56.1315 - Local<String> name(zone_);
56.1316 -
56.1317 - if (!fullTypeAndName(&returnType, name.ref(), DeclFun))
56.1318 - return NULL;
56.1319 -
56.1320 - SourcePosition pos = scanner_.begin();
56.1321 - ParameterList *parameters = new (pool_) ParameterList();
56.1322 -
56.1323 - if (!expect(TOK_LPAREN))
56.1324 - return NULL;
56.1325 -
56.1326 - bool variadic = false;
56.1327 -
56.1328 - if (!match(TOK_RPAREN)) {
56.1329 - while (true) {
56.1330 - TypeQualifiers quals = TypeQual_None;
56.1331 - if (match(TOK_CONST))
56.1332 - quals = TypeQualifiers(quals | TypeQual_Const);
56.1333 -
56.1334 - bool ref = match(TOK_AMPERSAND);
56.1335 -
56.1336 - SourcePosition begin = scanner_.begin();
56.1337 - Expression *type;
56.1338 - Local<String> name(zone_);
56.1339 - if (!fullTypeAndName(&type, name.ref(), DeclArg))
56.1340 - return NULL;
56.1341 -
56.1342 - if (!name) {
56.1343 - if ((quals & TypeQual_Const) || ref) {
56.1344 - cc_.reportError(begin, Message_InvalidVarArgs);
56.1345 - return NULL;
56.1346 - }
56.1347 -
56.1348 - if (token != TOK_NATIVE) {
56.1349 - cc_.reportError(begin, Message_VarArgsOutsideNative);
56.1350 - return NULL;
56.1351 - }
56.1352 -
56.1353 - variadic = true;
56.1354 - break;
56.1355 - }
56.1356 -
56.1357 - ExpressionList *dims = NULL;
56.1358 - if (peek(TOK_LBRACKET)) {
56.1359 - if ((dims = dimensions()) == NULL)
56.1360 - return NULL;
56.1361 - }
56.1362 -
56.1363 - Expression *expr = NULL;
56.1364 - if (match(TOK_ASSIGN)) {
56.1365 - if ((expr = expression()) == NULL)
56.1366 - return NULL;
56.1367 - }
56.1368 -
56.1369 - Parameter *parameter = new (pool_) Parameter(name, type, ref, quals, dims, expr, begin);
56.1370 - if (!parameters->append(parameter))
56.1371 - return NULL;
56.1372 -
56.1373 - if (!match(TOK_COMMA))
56.1374 - break;
56.1375 - }
56.1376 - if (!expect(TOK_RPAREN))
56.1377 - return NULL;
56.1378 - }
56.1379 -
56.1380 - encounteredReturn_ = false;
56.1381 -
56.1382 - Statement *body = NULL;
56.1383 - if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
56.1384 - body = block();
56.1385 - if (!body)
56.1386 - return NULL;
56.1387 - }
56.1388 -
56.1389 - FunctionSignature signature(returnType, parameters, variadic);
56.1390 - if (token == TOK_TYPEDEF)
56.1391 - return new (pool_) FunctionTypeStatement(pos, name, signature);
56.1392 -
56.1393 - return new (pool_) FunctionStatement(pos, name, token, body, signature, encounteredReturn_);
56.1394 -}
56.1395 -
56.1396 -static inline bool
56.1397 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
56.1398 -{
56.1399 - Local<String> tag(zone, zone->makeSymbol(name));
56.1400 - if (!tag)
56.1401 - return false;
56.1402 -
56.1403 - assert(false);
56.1404 - return false; //return !!scope->declareType(tag, type);
56.1405 -}
56.1406 -
56.1407 -static inline bool
56.1408 -DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
56.1409 -{
56.1410 - Local<Type> primitive(zone, zone->types()->getPrimitive(type));
56.1411 - assert(primitive);
56.1412 - return DeclareIntrinsicType(zone, scope, name, primitive);
56.1413 -}
56.1414 -
56.1415 -ParseTree *
56.1416 -Parser::parse()
56.1417 -{
56.1418 - StatementList *statements = new (pool_) StatementList();
56.1419 -
56.1420 - for (;;) {
56.1421 - Statement *statement = NULL;
56.1422 -
56.1423 - TokenKind kind = scanner_.peek();
56.1424 - switch (kind) {
56.1425 - case TOK_ERROR:
56.1426 - return NULL;
56.1427 -
56.1428 - case TOK_EOF:
56.1429 - break;
56.1430 -
56.1431 - case TOK_NAME:
56.1432 - if ((statement = function(TOK_NAME)) == NULL)
56.1433 - return NULL;
56.1434 - break;
56.1435 -
56.1436 - case TOK_FROM:
56.1437 - case TOK_IMPORT:
56.1438 - {
56.1439 - scanner_.scan();
56.1440 - if (statements->length())
56.1441 - cc_.reportError(scanner_.begin(), Message_ImportsMustBeFirst);
56.1442 - ImportStatement *stmt = import(kind);
56.1443 - if (!stmt)
56.1444 - return NULL;
56.1445 - if (!imports_->append(stmt))
56.1446 - return NULL;
56.1447 - if (!matchSemicolon())
56.1448 - return NULL;
56.1449 - continue;
56.1450 - }
56.1451 -
56.1452 - case TOK_FORWARD:
56.1453 - case TOK_PUBLIC:
56.1454 - case TOK_NATIVE:
56.1455 - case TOK_STOCK:
56.1456 - case TOK_LABEL:
56.1457 - case TOK_TYPEDEF:
56.1458 - {
56.1459 - if (kind != TOK_LABEL)
56.1460 - scanner_.scan();
56.1461 - if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
56.1462 - if ((statement = var(TypeQual_Const)) == NULL)
56.1463 - return NULL;
56.1464 - if (!matchSemicolon())
56.1465 - return NULL;
56.1466 - } else if (kind == TOK_PUBLIC && peek(TOK_ENUM)) {
56.1467 - if ((statement = enum_(kind)) == NULL)
56.1468 - return NULL;
56.1469 - if (!matchSemicolon())
56.1470 - return NULL;
56.1471 - } else {
56.1472 - if ((statement = function(kind)) == NULL)
56.1473 - return NULL;
56.1474 - if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
56.1475 - return NULL;
56.1476 - }
56.1477 - break;
56.1478 - }
56.1479 -
56.1480 - case TOK_CONST:
56.1481 - case TOK_NEW:
56.1482 - {
56.1483 - TypeQualifiers quals = (kind == TOK_CONST) ? TypeQual_Const : TypeQual_None;
56.1484 - // Note: at global scope, we don't accept comma-delimited
56.1485 - // declarations yet, to see if we can get away with forcing
56.1486 - // a nicer top-level style.
56.1487 - scanner_.scan();
56.1488 - if ((statement = var(quals)) == NULL)
56.1489 - return NULL;
56.1490 - if (!matchSemicolon())
56.1491 - return NULL;
56.1492 - break;
56.1493 - }
56.1494 -
56.1495 - case TOK_ENUM:
56.1496 - if ((statement = enum_(TOK_NONE)) == NULL)
56.1497 - return NULL;
56.1498 - if (!matchSemicolon())
56.1499 - return NULL;
56.1500 - break;
56.1501 -
56.1502 - case TOK_STRUCT:
56.1503 - if ((statement = struct_()) == NULL)
56.1504 - return NULL;
56.1505 - if (!matchSemicolon())
56.1506 - return NULL;
56.1507 - break;
56.1508 -
56.1509 - default:
56.1510 - cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
56.1511 - return NULL;
56.1512 - }
56.1513 -
56.1514 - if (!statement)
56.1515 - break;
56.1516 -
56.1517 - if (!statements->append(statement))
56.1518 - return NULL;
56.1519 - }
56.1520 -
56.1521 - return new (pool_) ParseTree(statements, unbound_, imports_);
56.1522 -}
56.1523 -
56.1524 -class AstPrinter : public AstVisitor
56.1525 -{
56.1526 - FILE *fp_;
56.1527 - size_t level_;
56.1528 -
56.1529 - private:
56.1530 - void prefix() {
56.1531 - for (size_t i = 0; i < level_; i++)
56.1532 - fprintf(fp_, " ");
56.1533 - }
56.1534 - void indent() {
56.1535 - level_++;
56.1536 - }
56.1537 - void unindent() {
56.1538 - level_--;
56.1539 - }
56.1540 -
56.1541 - public:
56.1542 - AstPrinter(FILE *fp)
56.1543 - : fp_(fp),
56.1544 - level_(0)
56.1545 - {
56.1546 - }
56.1547 -
56.1548 - void dump(const FunctionSignature &sig) {
56.1549 - prefix();
56.1550 - fprintf(fp_, "()\n");
56.1551 - }
56.1552 - void visitNameProxy(NameProxy *name) {
56.1553 - prefix();
56.1554 - fprintf(fp_, "[ NameProxy (%s)\n", name->name()->chars());
56.1555 - }
56.1556 - void visitCallExpression(CallExpression *node) {
56.1557 - prefix();
56.1558 - fprintf(fp_, "[ CallExpression\n");
56.1559 - indent();
56.1560 - node->callee()->accept(this);
56.1561 - for (size_t i = 0; i < node->arguments()->length(); i++)
56.1562 - node->arguments()->at(i)->accept(this);
56.1563 - unindent();
56.1564 - }
56.1565 - void visitFunctionTypeStatement(FunctionTypeStatement *node) {
56.1566 - prefix();
56.1567 - fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->name()->chars());
56.1568 - indent();
56.1569 - dump(node->signature());
56.1570 - unindent();
56.1571 - }
56.1572 - void visitFunctionStatement(FunctionStatement *node) {
56.1573 - prefix();
56.1574 - fprintf(fp_, "[ FunctionStatement (%s)\n", node->name()->chars());
56.1575 - indent();
56.1576 - dump(node->signature());
56.1577 - if (node->body())
56.1578 - node->body()->accept(this);
56.1579 - unindent();
56.1580 - }
56.1581 - void visitExpressionStatement(ExpressionStatement *node) {
56.1582 - prefix();
56.1583 - fprintf(fp_, "[ ExpressionStatement\n");
56.1584 - indent();
56.1585 - node->expression()->accept(this);
56.1586 - unindent();
56.1587 - }
56.1588 - void visitAssignment(Assignment *node) {
56.1589 - prefix();
56.1590 - fprintf(fp_, "[ Assignment\n");
56.1591 - indent();
56.1592 - node->lvalue()->accept(this);
56.1593 - node->expression()->accept(this);
56.1594 - unindent();
56.1595 - }
56.1596 - void visitTernaryExpression(TernaryExpression *node) {
56.1597 - prefix();
56.1598 - fprintf(fp_, "[ TernaryExpression\n");
56.1599 - indent();
56.1600 - node->condition()->accept(this);
56.1601 - node->left()->accept(this);
56.1602 - node->right()->accept(this);
56.1603 - unindent();
56.1604 - }
56.1605 - void visitBinaryExpression(BinaryExpression *node) {
56.1606 - prefix();
56.1607 - fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
56.1608 - indent();
56.1609 - node->left()->accept(this);
56.1610 - node->right()->accept(this);
56.1611 - unindent();
56.1612 - }
56.1613 - void visitUnaryExpression(UnaryExpression *node) {
56.1614 - prefix();
56.1615 - fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
56.1616 - indent();
56.1617 - node->expression()->accept(this);
56.1618 - unindent();
56.1619 - }
56.1620 - void visitReturnStatement(ReturnStatement *node) {
56.1621 - prefix();
56.1622 - fprintf(fp_, "[ ReturnStatement\n");
56.1623 - indent();
56.1624 - if (node->expression())
56.1625 - node->expression()->accept(this);
56.1626 - unindent();
56.1627 - }
56.1628 - void visitForStatement(ForStatement *node) {
56.1629 - prefix();
56.1630 - fprintf(fp_, "[ ForStatement\n");
56.1631 - indent();
56.1632 - if (node->initialization())
56.1633 - node->initialization()->accept(this);
56.1634 - if (node->condition())
56.1635 - node->condition()->accept(this);
56.1636 - if (node->update())
56.1637 - node->update()->accept(this);
56.1638 - node->body()->accept(this);
56.1639 - unindent();
56.1640 - }
56.1641 - void visitBlockStatement(BlockStatement *node) {
56.1642 - prefix();
56.1643 - fprintf(fp_, "[ BlockStatement\n");
56.1644 - indent();
56.1645 - for (size_t i = 0; i < node->statements()->length(); i++)
56.1646 - node->statements()->at(i)->accept(this);
56.1647 - unindent();
56.1648 - }
56.1649 - void visitVariableDeclaration(VariableDeclaration *node) {
56.1650 - prefix();
56.1651 - fprintf(fp_, "[ VariableDeclaration (%s)\n", node->name()->chars());
56.1652 - indent();
56.1653 - if (node->initialization())
56.1654 - node->initialization()->accept(this);
56.1655 - unindent();
56.1656 - }
56.1657 - void visitIntegerLiteral(IntegerLiteral *node) {
56.1658 - prefix();
56.1659 - fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
56.1660 - }
56.1661 - void visitBooleanLiteral(BooleanLiteral *node) {
56.1662 - prefix();
56.1663 - fprintf(fp_, "[ BooleanLiteral (%s)\n",
56.1664 - (node->token() == TOK_TRUE) ? "true" : "false");
56.1665 - }
56.1666 - void visitFloatLiteral(FloatLiteral *node) {
56.1667 - prefix();
56.1668 - fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
56.1669 - }
56.1670 - void visitIfStatement(IfStatement *node) {
56.1671 - prefix();
56.1672 - fprintf(fp_, "[ IfStatement\n");
56.1673 - indent();
56.1674 - node->ifTrue()->accept(this);
56.1675 - if (node->ifFalse())
56.1676 - node->ifFalse()->accept(this);
56.1677 - unindent();
56.1678 - }
56.1679 - void visitIndexExpression(IndexExpression *node) {
56.1680 - prefix();
56.1681 - fprintf(fp_, "[ IndexExpression\n");
56.1682 - indent();
56.1683 - node->left()->accept(this);
56.1684 - node->right()->accept(this);
56.1685 - unindent();
56.1686 - }
56.1687 - void visitEnumStatement(EnumStatement *node) {
56.1688 - prefix();
56.1689 - fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
56.1690 - indent();
56.1691 - for (size_t i = 0; i < node->entries()->length(); i++) {
56.1692 - prefix();
56.1693 - fprintf(fp_, "%s =\n", node->entries()->at(i).name->chars());
56.1694 - if (node->entries()->at(i).expr) {
56.1695 - indent();
56.1696 - node->entries()->at(i).expr->accept(this);
56.1697 - unindent();
56.1698 - }
56.1699 - }
56.1700 - unindent();
56.1701 - }
56.1702 - void visitWhileStatement(WhileStatement *node) {
56.1703 - prefix();
56.1704 - fprintf(fp_, "[ WhileStatement (%s)\n",
56.1705 - (node->token() == TOK_DO) ? "do" : "while");
56.1706 - indent();
56.1707 - if (node->token() == TOK_DO) {
56.1708 - node->condition()->accept(this);
56.1709 - node->body()->accept(this);
56.1710 - } else {
56.1711 - node->condition()->accept(this);
56.1712 - node->body()->accept(this);
56.1713 - }
56.1714 - unindent();
56.1715 - }
56.1716 - void visitBreakStatement(BreakStatement *node) {
56.1717 - prefix();
56.1718 - fprintf(fp_, "[ BreakStatement\n");
56.1719 - }
56.1720 - void visitContinueStatement(ContinueStatement *node) {
56.1721 - prefix();
56.1722 - fprintf(fp_, "[ ContinueStatement\n");
56.1723 - }
56.1724 - void visitStringLiteral(StringLiteral *node) {
56.1725 - prefix();
56.1726 - fprintf(fp_, "[ StringLiteral\n");
56.1727 - }
56.1728 - void visitIncDecExpression(IncDecExpression *node) {
56.1729 - prefix();
56.1730 - fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
56.1731 - indent();
56.1732 - node->expression()->accept(this);
56.1733 - unindent();
56.1734 - }
56.1735 - void visitStructureStatement(StructureStatement *node) {
56.1736 - prefix();
56.1737 - fprintf(fp_, "[ StructureStatement %s\n", node->name()->chars());
56.1738 - }
56.1739 - void visitFieldExpression(FieldExpression *node) {
56.1740 - prefix();
56.1741 - fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
56.1742 - indent();
56.1743 - node->left()->accept(this);
56.1744 - unindent();
56.1745 - }
56.1746 - void visitSwitchStatement(SwitchStatement *node) {
56.1747 - prefix();
56.1748 - fprintf(fp_, "[ SwitchStatement\n");
56.1749 - indent();
56.1750 - node->expression()->accept(this);
56.1751 - for (size_t i = 0; i < node->cases()->length(); i++) {
56.1752 - Case *c = node->cases()->at(i);
56.1753 - c->expression()->accept(this);
56.1754 - if (c->others()) {
56.1755 - for (size_t j = 0; j < c->others()->length(); j++)
56.1756 - c->others()->at(j)->accept(this);
56.1757 - }
56.1758 - indent();
56.1759 - c->statement()->accept(this);
56.1760 - unindent();
56.1761 - }
56.1762 - if (node->defaultCase())
56.1763 - node->defaultCase()->accept(this);
56.1764 - unindent();
56.1765 - }
56.1766 - void visitArrayLiteral(ArrayLiteral *node) {
56.1767 - prefix();
56.1768 - fprintf(fp_, "[ ArrayLiteral\n");
56.1769 - indent();
56.1770 - for (size_t i = 0; i < node->expressions()->length(); i++) {
56.1771 - Expression *expr = node->expressions()->at(i);
56.1772 - indent();
56.1773 - expr->accept(this);
56.1774 - unindent();
56.1775 - }
56.1776 - }
56.1777 - void visitImportStatement(ImportStatement *node) {
56.1778 - prefix();
56.1779 - fprintf(fp_, "[ ImportStatement\n");
56.1780 - }
56.1781 -};
56.1782 -
56.1783 -void
56.1784 -ParseTree::dump(FILE *fp)
56.1785 -{
56.1786 - AstPrinter printer(fp);
56.1787 -
56.1788 - for (size_t i = 0; i < statements_->length(); i++)
56.1789 - statements_->at(i)->accept(&printer);
56.1790 -}
56.1791 +/* vim: set ts=4 sw=4 tw=99 et:
56.1792 + *
56.1793 + * Copyright (C) 2012 David Anderson
56.1794 + *
56.1795 + * This file is part of SourcePawn.
56.1796 + *
56.1797 + * SourcePawn is free software: you can redistribute it and/or modify it under
56.1798 + * the terms of the GNU General Public License as published by the Free
56.1799 + * Software Foundation, either version 3 of the License, or (at your option)
56.1800 + * any later version.
56.1801 + *
56.1802 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
56.1803 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
56.1804 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
56.1805 + *
56.1806 + * You should have received a copy of the GNU General Public License along with
56.1807 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
56.1808 + */
56.1809 +#include <string.h>
56.1810 +#include "../Zone.h"
56.1811 +#include "../FixedArray.h"
56.1812 +#include "../Heap.h"
56.1813 +#include "../Strings.h"
56.1814 +#include "../TypeManager.h"
56.1815 +#include "Parser.h"
56.1816 +#include "../Heap-inl.h"
56.1817 +
56.1818 +using namespace ke;
56.1819 +
56.1820 +Parser::Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length)
56.1821 + : zone_(zone),
56.1822 + cc_(cc),
56.1823 + pool_(zone_->pool()),
56.1824 + scanner_(cc, stream, length),
56.1825 + unbound_(NULL)
56.1826 +{
56.1827 + unbound_ = new (pool_) PoolList<NameProxy *>();
56.1828 + imports_ = new (pool_) PoolList<ImportStatement *>();
56.1829 +}
56.1830 +
56.1831 +bool
56.1832 +Parser::peek(TokenKind kind)
56.1833 +{
56.1834 + return scanner_.peek() == kind;
56.1835 +}
56.1836 +
56.1837 +bool
56.1838 +Parser::match(TokenKind kind)
56.1839 +{
56.1840 + if (!peek(kind))
56.1841 + return false;
56.1842 + scanner_.scan();
56.1843 + return true;
56.1844 +}
56.1845 +
56.1846 +bool
56.1847 +Parser::matchSemicolon()
56.1848 +{
56.1849 + return expect(TOK_SEMICOLON);
56.1850 +}
56.1851 +
56.1852 +bool
56.1853 +Parser::expect(TokenKind kind)
56.1854 +{
56.1855 + TokenKind got = scanner_.scan();
56.1856 + if (got == kind)
56.1857 + return true;
56.1858 + cc_.reportError(scanner_.begin(), Message_WrongToken, TokenNames[kind], TokenNames[got]);
56.1859 + return false;
56.1860 +}
56.1861 +
56.1862 +bool
56.1863 +Parser::matchName(String **name, TokenKind kind)
56.1864 +{
56.1865 + assert(kind == TOK_NAME || kind == TOK_LABEL);
56.1866 + *name = NULL;
56.1867 + if (!match(kind))
56.1868 + return false;
56.1869 + *name = zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
56.1870 + return true;
56.1871 +}
56.1872 +
56.1873 +String *
56.1874 +Parser::expectName()
56.1875 +{
56.1876 + if (!expect(TOK_NAME))
56.1877 + return NULL;
56.1878 + return zone_->makeSymbol(scanner_.literal(), scanner_.literal_length());
56.1879 +}
56.1880 +
56.1881 +Expression *
56.1882 +Parser::primitive()
56.1883 +{
56.1884 + TokenKind kind = scanner_.peek();
56.1885 + switch (kind) {
56.1886 + case TOK_FLOAT_LITERAL:
56.1887 + {
56.1888 + scanner_.scan();
56.1889 + double value = Scanner::ParseDouble(scanner_.literal());
56.1890 + return new (pool_) FloatLiteral(scanner_.begin(), value);
56.1891 + }
56.1892 +
56.1893 + case TOK_HEX_LITERAL:
56.1894 + {
56.1895 + scanner_.scan();
56.1896 + int value = strtol(scanner_.literal(), NULL, 16);
56.1897 + return new (pool_) IntegerLiteral(scanner_.begin(), value);
56.1898 + }
56.1899 +
56.1900 + case TOK_INTEGER_LITERAL:
56.1901 + {
56.1902 + scanner_.scan();
56.1903 + int value = atoi(scanner_.literal());
56.1904 + return new (pool_) IntegerLiteral(scanner_.begin(), value);
56.1905 + }
56.1906 +
56.1907 + case TOK_TRUE:
56.1908 + case TOK_FALSE:
56.1909 + scanner_.scan();
56.1910 + return new (pool_) BooleanLiteral(scanner_.begin(), kind);
56.1911 +
56.1912 + case TOK_STRING_LITERAL:
56.1913 + {
56.1914 + scanner_.scan();
56.1915 + Local<String> string(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.1916 + return new (pool_) StringLiteral(scanner_.begin(), string);
56.1917 + }
56.1918 +
56.1919 + default:
56.1920 + {
56.1921 + if (kind != TOK_ERROR)
56.1922 + cc_.reportError(scanner_.begin(), Message_ExpectedExpression, TokenNames[kind]);
56.1923 + return NULL;
56.1924 + }
56.1925 + }
56.1926 +}
56.1927 +
56.1928 +Expression *
56.1929 +Parser::fixedArrayLiteral()
56.1930 +{
56.1931 + SourcePosition pos = scanner_.begin();
56.1932 +
56.1933 + ExpressionList *list = new (pool_) ExpressionList();
56.1934 + do {
56.1935 + // { } is an illegal array literal.
56.1936 + if (list->length() > 0 && match(TOK_LBRACE))
56.1937 + break;
56.1938 +
56.1939 + Expression *expr = NULL;
56.1940 + if (peek(TOK_LBRACE))
56.1941 + expr = fixedArrayLiteral();
56.1942 + else
56.1943 + expr = primitive();
56.1944 + if (!expr)
56.1945 + return NULL;
56.1946 +
56.1947 + if (!list->append(expr))
56.1948 + return NULL;
56.1949 +
56.1950 + if (!match(TOK_COMMA)) {
56.1951 + if (!expect(TOK_RBRACE))
56.1952 + return NULL;
56.1953 + break;
56.1954 + }
56.1955 + } while (true);
56.1956 +
56.1957 + return new (pool_) ArrayLiteral(pos, TOK_LBRACE, list);
56.1958 +}
56.1959 +
56.1960 +Expression *
56.1961 +Parser::prefix()
56.1962 +{
56.1963 + switch (scanner_.peek()) {
56.1964 + case TOK_LPAREN:
56.1965 + {
56.1966 + scanner_.scan();
56.1967 + Expression *expr = expression();
56.1968 + if (!expr)
56.1969 + return NULL;
56.1970 + if (!expect(TOK_RPAREN))
56.1971 + return NULL;
56.1972 + return expr;
56.1973 + }
56.1974 +
56.1975 + case TOK_NAME:
56.1976 + {
56.1977 + Local<String> name(zone_, expectName());
56.1978 + if (!name)
56.1979 + return NULL;
56.1980 + return new (pool_) NameProxy(scanner_.begin(), name);
56.1981 + }
56.1982 +
56.1983 + default:
56.1984 + return primitive();
56.1985 + }
56.1986 +}
56.1987 +
56.1988 +// Parses only old-style declarations.
56.1989 +bool
56.1990 +Parser::typeAndName(Expression **type, String **namep)
56.1991 +{
56.1992 + if (match(TOK_LABEL)) {
56.1993 + // Old-style declaration:
56.1994 + // new X:type
56.1995 + Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.1996 + if (!name)
56.1997 + return false;
56.1998 +
56.1999 + *type = new (pool_) NameProxy(scanner_.begin(), name);
56.2000 + *namep = expectName();
56.2001 + return !!*namep;
56.2002 + }
56.2003 +
56.2004 + *type = NULL;
56.2005 + *namep = expectName();
56.2006 +
56.2007 + return !!*namep;
56.2008 +}
56.2009 +
56.2010 +// Parses both old and new style declarations.
56.2011 +bool
56.2012 +Parser::fullTypeAndName(Expression **type, String **namep, DeclKind kind)
56.2013 +{
56.2014 + // decl ::= newdecl | olddecl
56.2015 + // newdecl ::= Type Ident
56.2016 + // olddecl ::= Label? (Ident | "...")
56.2017 + // type ::= Ident
56.2018 + // label ::= Ident ":"
56.2019 + //
56.2020 + if (match(TOK_LABEL)) {
56.2021 + // We something of the form:
56.2022 + // Label Ident
56.2023 + // or: Label "..."
56.2024 + Local<String> name(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.2025 + if (!name)
56.2026 + return false;
56.2027 +
56.2028 + *type = new (pool_) NameProxy(scanner_.begin(), name);
56.2029 + if (kind == DeclArg && match(TOK_ELLIPSES)) {
56.2030 + *namep = NULL;
56.2031 + } else {
56.2032 + if ((*namep = expectName()) == NULL)
56.2033 + return false;
56.2034 + }
56.2035 + return true;
56.2036 + }
56.2037 +
56.2038 + Local<String> name(zone_, expectName());
56.2039 + if (!name)
56.2040 + return false;
56.2041 +
56.2042 + if (peek(TOK_NAME) || (kind == DeclArg && peek(TOK_ELLIPSES))) {
56.2043 + // We got something of the form:
56.2044 + // Ident Ident
56.2045 + *type = new (pool_) NameProxy(scanner_.begin(), name);
56.2046 + if (peek(TOK_NAME)) {
56.2047 + if ((*namep = expectName()) == NULL)
56.2048 + return false;
56.2049 + } else {
56.2050 + *namep = NULL;
56.2051 + }
56.2052 + return true;
56.2053 + }
56.2054 +
56.2055 + // We got something of the form:
56.2056 + // Ident
56.2057 + *type = NULL;
56.2058 + *namep = name;
56.2059 + return true;
56.2060 +}
56.2061 +
56.2062 +Expression *
56.2063 +Parser::call(Expression *callee)
56.2064 +{
56.2065 + ExpressionList *arguments = new (pool_) ExpressionList();
56.2066 +
56.2067 + SourcePosition pos = scanner_.begin();
56.2068 + expect(TOK_LPAREN);
56.2069 +
56.2070 + if (!match(TOK_RPAREN)) {
56.2071 + while (true) {
56.2072 + Expression *expr = expression();
56.2073 + if (!expr)
56.2074 + return NULL;
56.2075 +
56.2076 + if (!arguments->append(expr))
56.2077 + return NULL;
56.2078 +
56.2079 + if (!match(TOK_COMMA))
56.2080 + break;
56.2081 + }
56.2082 +
56.2083 + if (!expect(TOK_RPAREN))
56.2084 + return NULL;
56.2085 + }
56.2086 +
56.2087 + return new (pool_) CallExpression(pos, callee, arguments);
56.2088 +}
56.2089 +
56.2090 +Expression *
56.2091 +Parser::index(Expression *left)
56.2092 +{
56.2093 + expect(TOK_LBRACKET);
56.2094 +
56.2095 + SourcePosition pos = scanner_.begin();
56.2096 + Expression *expr = expression();
56.2097 + if (!expr)
56.2098 + return NULL;
56.2099 +
56.2100 + if (!expect(TOK_RBRACKET))
56.2101 + return NULL;
56.2102 +
56.2103 + return new (pool_) IndexExpression(pos, left, expr);
56.2104 +}
56.2105 +
56.2106 +Expression *
56.2107 +Parser::field(Expression *left)
56.2108 +{
56.2109 + expect(TOK_DOT);
56.2110 +
56.2111 + SourcePosition pos = scanner_.begin();
56.2112 + Local<String> name(zone_, expectName());
56.2113 + if (!name)
56.2114 + return NULL;
56.2115 +
56.2116 + return new (pool_) FieldExpression(pos, left, name);
56.2117 +}
56.2118 +
56.2119 +Expression *
56.2120 +Parser::primary()
56.2121 +{
56.2122 + Expression *expr = prefix();
56.2123 + if (!expr)
56.2124 + return NULL;
56.2125 +
56.2126 + for (;;) {
56.2127 + switch (scanner_.peek()) {
56.2128 + case TOK_LPAREN:
56.2129 + if ((expr = call(expr)) == NULL)
56.2130 + return NULL;
56.2131 + break;
56.2132 +
56.2133 + case TOK_LBRACKET:
56.2134 + if ((expr = index(expr)) == NULL)
56.2135 + return NULL;
56.2136 + break;
56.2137 +
56.2138 + case TOK_DOT:
56.2139 + if ((expr = field(expr)) == NULL)
56.2140 + return NULL;
56.2141 + break;
56.2142 +
56.2143 + default:
56.2144 + return expr;
56.2145 + }
56.2146 + }
56.2147 +}
56.2148 +
56.2149 +Expression *
56.2150 +Parser::unary()
56.2151 +{
56.2152 + TokenKind token = scanner_.peek();
56.2153 +
56.2154 + SourcePosition pos = scanner_.begin();
56.2155 + switch (token) {
56.2156 + case TOK_INCREMENT:
56.2157 + case TOK_DECREMENT:
56.2158 + {
56.2159 + scanner_.scan();
56.2160 + Expression *expr = unary();
56.2161 + if (!expr)
56.2162 + return NULL;
56.2163 + return new (pool_) IncDecExpression(pos, token, expr, false);
56.2164 + }
56.2165 +
56.2166 + case TOK_MINUS:
56.2167 + case TOK_NOT:
56.2168 + case TOK_TILDE:
56.2169 + {
56.2170 + scanner_.scan();
56.2171 + Expression *expr = unary();
56.2172 + if (!expr)
56.2173 + return NULL;
56.2174 + return new (pool_) UnaryExpression(pos, token, expr);
56.2175 + }
56.2176 +
56.2177 + case TOK_SIZEOF:
56.2178 + {
56.2179 + scanner_.scan();
56.2180 + if (!expect(TOK_LPAREN))
56.2181 + return NULL;
56.2182 + Expression *expr = unary();
56.2183 + if (!expr)
56.2184 + return NULL;
56.2185 + if (!expect(TOK_RPAREN))
56.2186 + return NULL;
56.2187 + return new (pool_) UnaryExpression(pos, token, expr);
56.2188 + }
56.2189 +
56.2190 + case TOK_LABEL:
56.2191 + {
56.2192 + scanner_.scan();
56.2193 + Local<String> tag(zone_, zone_->makeSymbol(scanner_.literal(), scanner_.literal_length()));
56.2194 + if (!tag)
56.2195 + return NULL;
56.2196 +
56.2197 + NameProxy *proxy = new (pool_) NameProxy(scanner_.begin(), tag);
56.2198 +
56.2199 + Expression *expr = unary();
56.2200 + if (!expr)
56.2201 + return NULL;
56.2202 +
56.2203 + return new (pool_) UnaryExpression(pos, TOK_LABEL, expr, proxy);
56.2204 + }
56.2205 +
56.2206 + default:
56.2207 + break;
56.2208 + }
56.2209 +
56.2210 + Expression *expr = primary();
56.2211 +
56.2212 + token = scanner_.peek();
56.2213 + if (token == TOK_INCREMENT || token == TOK_DECREMENT) {
56.2214 + scanner_.scan();
56.2215 + return new (pool_) IncDecExpression(pos, token, expr, true);
56.2216 + }
56.2217 +
56.2218 + return expr;
56.2219 +}
56.2220 +
56.2221 +Expression *
56.2222 +Parser::multiplication()
56.2223 +{
56.2224 + Expression *left = unary();
56.2225 + do {
56.2226 + if (!match(TOK_SLASH) && !match(TOK_STAR) && !match(TOK_PERCENT))
56.2227 + break;
56.2228 + SourcePosition pos = scanner_.begin();
56.2229 + TokenKind kind = scanner_.last();
56.2230 + Expression *right = unary();
56.2231 + if (!right)
56.2232 + return NULL;
56.2233 + left = new (pool_) BinaryExpression(pos, kind, left, right);
56.2234 + } while (left);
56.2235 + return left;
56.2236 +}
56.2237 +
56.2238 +Expression *
56.2239 +Parser::addition()
56.2240 +{
56.2241 + Expression *left = multiplication();
56.2242 + while (left) {
56.2243 + if (!match(TOK_PLUS) && !match(TOK_MINUS))
56.2244 + break;
56.2245 + SourcePosition pos = scanner_.begin();
56.2246 + TokenKind kind = scanner_.last();
56.2247 + Expression *right = multiplication();
56.2248 + if (!right)
56.2249 + return NULL;
56.2250 + left = new (pool_) BinaryExpression(pos, kind, left, right);
56.2251 + }
56.2252 + return left;
56.2253 +}
56.2254 +
56.2255 +Expression *
56.2256 +Parser::shift()
56.2257 +{
56.2258 + Expression *left = addition();
56.2259 + while (left) {
56.2260 + if (!match(TOK_SHL) && !match(TOK_SHR) && !match(TOK_USHR))
56.2261 + break;
56.2262 + SourcePosition pos = scanner_.begin();
56.2263 + TokenKind kind = scanner_.last();
56.2264 + Expression *right = addition();
56.2265 + if (!right)
56.2266 + return NULL;
56.2267 + left = new (pool_) BinaryExpression(pos, kind, left, right);
56.2268 + }
56.2269 + return left;
56.2270 +}
56.2271 +
56.2272 +Expression *
56.2273 +Parser::bitand_()
56.2274 +{
56.2275 + Expression *left = shift();
56.2276 + while (left) {
56.2277 + if (!match(TOK_BITAND))
56.2278 + break;
56.2279 + SourcePosition pos = scanner_.begin();
56.2280 + Expression *right = shift();
56.2281 + if (!right)
56.2282 + return NULL;
56.2283 + left = new (pool_) BinaryExpression(pos, TOK_BITAND, left, right);
56.2284 + }
56.2285 + return left;
56.2286 +}
56.2287 +
56.2288 +Expression *
56.2289 +Parser::bitxor()
56.2290 +{
56.2291 + Expression *left = bitand_();
56.2292 + while (left) {
56.2293 + if (!match(TOK_BITXOR))
56.2294 + break;
56.2295 + SourcePosition pos = scanner_.begin();
56.2296 + Expression *right = shift();
56.2297 + if (!right)
56.2298 + return NULL;
56.2299 + left = new (pool_) BinaryExpression(pos, TOK_BITXOR, left, right);
56.2300 + }
56.2301 + return left;
56.2302 +}
56.2303 +
56.2304 +Expression *
56.2305 +Parser::bitor_()
56.2306 +{
56.2307 + Expression *left = bitxor();
56.2308 + while (left) {
56.2309 + if (!match(TOK_BITOR))
56.2310 + break;
56.2311 + SourcePosition pos = scanner_.begin();
56.2312 + Expression *right = bitxor();
56.2313 + if (!right)
56.2314 + return NULL;
56.2315 + left = new (pool_) BinaryExpression(pos, TOK_BITOR, left, right);
56.2316 + }
56.2317 + return left;
56.2318 +}
56.2319 +
56.2320 +Expression *
56.2321 +Parser::relational()
56.2322 +{
56.2323 + Expression *left = bitor_();
56.2324 + while (left) {
56.2325 + TokenKind kind = scanner_.peek();
56.2326 + if (kind < TOK_LT || kind > TOK_GE)
56.2327 + break;
56.2328 + scanner_.scan();
56.2329 + SourcePosition pos = scanner_.begin();
56.2330 + Expression *right = shift();
56.2331 + if (!right)
56.2332 + return NULL;
56.2333 + left = new (pool_) BinaryExpression(pos, kind, left, right);
56.2334 + }
56.2335 + return left;
56.2336 +}
56.2337 +
56.2338 +Expression *
56.2339 +Parser::equals()
56.2340 +{
56.2341 + Expression *left = relational();
56.2342 + while (left) {
56.2343 + if (!match(TOK_EQUALS) && !match(TOK_NOTEQUALS))
56.2344 + break;
56.2345 + TokenKind kind = scanner_.last();
56.2346 + SourcePosition pos = scanner_.begin();
56.2347 + Expression *right = relational();
56.2348 + if (!right)
56.2349 + return NULL;
56.2350 + left = new (pool_) BinaryExpression(pos, kind, left, right);
56.2351 + }
56.2352 + return left;
56.2353 +}
56.2354 +
56.2355 +Expression *
56.2356 +Parser::and_()
56.2357 +{
56.2358 + Expression *left = equals();
56.2359 + while (left) {
56.2360 + if (!match(TOK_AND))
56.2361 + break;
56.2362 + SourcePosition pos = scanner_.begin();
56.2363 + Expression *right = equals();
56.2364 + if (!right)
56.2365 + return NULL;
56.2366 + left = new (pool_) BinaryExpression(pos, TOK_AND, left, right);
56.2367 + }
56.2368 + return left;
56.2369 +}
56.2370 +
56.2371 +Expression *
56.2372 +Parser::or_()
56.2373 +{
56.2374 + Expression *left = and_();
56.2375 + while (left) {
56.2376 + if (!match(TOK_OR))
56.2377 + break;
56.2378 + SourcePosition pos = scanner_.begin();
56.2379 + Expression *right = and_();
56.2380 + if (!right)
56.2381 + return NULL;
56.2382 + left = new (pool_) BinaryExpression(pos, TOK_OR, left, right);
56.2383 + }
56.2384 + return left;
56.2385 +}
56.2386 +
56.2387 +Expression *
56.2388 +Parser::ternary()
56.2389 +{
56.2390 + Expression *cond = or_();
56.2391 + if (!cond)
56.2392 + return NULL;
56.2393 +
56.2394 + if (!match(TOK_QMARK))
56.2395 + return cond;
56.2396 +
56.2397 + Expression *left;
56.2398 + SourcePosition pos = scanner_.begin();
56.2399 + AutoAllowTags<false> disableTags(scanner_);
56.2400 + {
56.2401 + if ((left = expression()) == NULL)
56.2402 + return NULL;
56.2403 + }
56.2404 +
56.2405 + if (!expect(TOK_COLON))
56.2406 + return NULL;
56.2407 +
56.2408 + Expression *right = expression();
56.2409 + if (!right)
56.2410 + return NULL;
56.2411 +
56.2412 + return new (pool_) TernaryExpression(pos, cond, left, right);
56.2413 +}
56.2414 +
56.2415 +Expression *
56.2416 +Parser::assignment()
56.2417 +{
56.2418 + Expression *left = ternary();
56.2419 + while (left) {
56.2420 + TokenKind token = scanner_.peek();
56.2421 + if (token != TOK_ASSIGN && (token < TOK_ASSIGN_ADD || token > TOK_ASSIGN_SHL))
56.2422 + break;
56.2423 + scanner_.scan();
56.2424 + SourcePosition pos = scanner_.begin();
56.2425 + Expression *expr = ternary();
56.2426 + if (!expr)
56.2427 + return NULL;
56.2428 +
56.2429 + left = new (pool_) Assignment(pos, token, left, expr);
56.2430 + }
56.2431 + return left;
56.2432 +}
56.2433 +
56.2434 +Expression *
56.2435 +Parser::expression()
56.2436 +{
56.2437 + return assignment();
56.2438 +}
56.2439 +
56.2440 +Statement *
56.2441 +Parser::while_()
56.2442 +{
56.2443 + // while ::= "while" "(" expr ")" statement
56.2444 + SourcePosition pos = scanner_.begin();
56.2445 + scanner_.scan();
56.2446 +
56.2447 + if (!expect(TOK_LPAREN))
56.2448 + return NULL;
56.2449 +
56.2450 + Expression *condition = expression();
56.2451 + if (!condition)
56.2452 + return NULL;
56.2453 +
56.2454 + if (!expect(TOK_RPAREN))
56.2455 + return NULL;
56.2456 +
56.2457 + Statement *body;
56.2458 + if (scanner_.peek() == TOK_LBRACE)
56.2459 + body = block();
56.2460 + else
56.2461 + body = localStatement();
56.2462 + if (!body)
56.2463 + return NULL;
56.2464 +
56.2465 + return new (pool_) WhileStatement(pos, TOK_WHILE, condition, body);
56.2466 +}
56.2467 +
56.2468 +Statement *
56.2469 +Parser::do_()
56.2470 +{
56.2471 + // do ::= "do" block "while" "(" expr ")"
56.2472 + SourcePosition pos = scanner_.begin();
56.2473 + scanner_.scan();
56.2474 +
56.2475 + Statement *body = block();
56.2476 + if (!body)
56.2477 + return NULL;
56.2478 +
56.2479 + if (!expect(TOK_WHILE))
56.2480 + return NULL;
56.2481 +
56.2482 + if (!expect(TOK_LPAREN))
56.2483 + return NULL;
56.2484 + Expression *condition = expression();
56.2485 + if (!condition)
56.2486 + return NULL;
56.2487 + if (!expect(TOK_RPAREN))
56.2488 + return NULL;
56.2489 +
56.2490 + return new (pool_) WhileStatement(pos, TOK_DO, condition, body);
56.2491 +}
56.2492 +
56.2493 +Statement *
56.2494 +Parser::switch_()
56.2495 +{
56.2496 + // switch ::= "switch" "(" expr ")" "{" case* defaultcase? "}"
56.2497 + // case ::= "case" casevals ":" statement
56.2498 + // defaultcase ::= "default" ":" statement
56.2499 + //
56.2500 + expect(TOK_SWITCH);
56.2501 +
56.2502 + SourcePosition pos = scanner_.begin();
56.2503 +
56.2504 + if (!expect(TOK_LPAREN))
56.2505 + return NULL;
56.2506 + Expression *expr = expression();
56.2507 + if (!expr)
56.2508 + return NULL;
56.2509 + if (!expect(TOK_RPAREN))
56.2510 + return NULL;
56.2511 +
56.2512 + if (!expect(TOK_LBRACE))
56.2513 + return NULL;
56.2514 +
56.2515 + SourcePosition defaultPos;
56.2516 + PoolList<Case *> *cases = new (pool_) PoolList<Case *>();
56.2517 +
56.2518 + Statement *defaultCase = NULL;
56.2519 +
56.2520 + while (!peek(TOK_RBRACE)) {
56.2521 + Expression *expr = NULL;
56.2522 + ExpressionList *others = NULL;
56.2523 + if (match(TOK_DEFAULT)) {
56.2524 + if (defaultCase) {
56.2525 + cc_.reportError(scanner_.begin(), Message_OneDefaultPerSwitch);
56.2526 + return NULL;
56.2527 + }
56.2528 +
56.2529 + defaultPos = scanner_.begin();
56.2530 + } else {
56.2531 + if (defaultCase) {
56.2532 + cc_.reportError(defaultPos, Message_DefaultMustBeLastCase);
56.2533 + return NULL;
56.2534 + }
56.2535 +
56.2536 + if (!expect(TOK_CASE))
56.2537 + return NULL;
56.2538 +
56.2539 + // A limitation in the grammar is that |case <NAME>:| will be
56.2540 + // detected as a label.
56.2541 + AutoAllowTags<false> disableTags(scanner_);
56.2542 +
56.2543 + if ((expr = expression()) == NULL)
56.2544 + return NULL;
56.2545 +
56.2546 + if (peek(TOK_COMMA)) {
56.2547 + others = new (pool_) ExpressionList();
56.2548 + while (match(TOK_COMMA)) {
56.2549 + Expression *other = expression();
56.2550 + if (!other)
56.2551 + return NULL;
56.2552 + if (!others->append(other))
56.2553 + return NULL;
56.2554 + }
56.2555 + }
56.2556 + }
56.2557 +
56.2558 + if (!expect(TOK_COLON))
56.2559 + return NULL;
56.2560 +
56.2561 + Statement *statement = localStatement();
56.2562 + if (!statement)
56.2563 + return NULL;
56.2564 +
56.2565 + if (!peek(TOK_CASE) &&
56.2566 + !peek(TOK_DEFAULT) &&
56.2567 + !peek(TOK_RBRACE))
56.2568 + {
56.2569 + cc_.reportError(scanner_.begin(), Message_SingleStatementPerCase);
56.2570 + return NULL;
56.2571 + }
56.2572 +
56.2573 + if (expr) {
56.2574 + Case *caze = new (pool_) Case(expr, others, statement);
56.2575 + if (!cases->append(caze))
56.2576 + return NULL;
56.2577 + } else {
56.2578 + defaultCase = statement;
56.2579 + }
56.2580 + }
56.2581 +
56.2582 + if (!expect(TOK_RBRACE))
56.2583 + return NULL;
56.2584 +
56.2585 + return new (pool_) SwitchStatement(pos, expr, cases, defaultCase);
56.2586 +}
56.2587 +
56.2588 +Statement *
56.2589 +Parser::forStatement()
56.2590 +{
56.2591 + // for ::= "for" "(" forinit? ";" forcond? ";" forstep ")" statement
56.2592 + // forint ::= "new" vardecl |
56.2593 + // exprstmt
56.2594 + // forcond ::= expr
56.2595 + // forstep ::= exprstmt
56.2596 + //
56.2597 + SourcePosition pos = scanner_.begin();
56.2598 + scanner_.scan();
56.2599 + if (!expect(TOK_LPAREN))
56.2600 + return NULL;
56.2601 +
56.2602 + Statement *decl = NULL;
56.2603 + if (!match(TOK_SEMICOLON)) {
56.2604 + if (match(TOK_NEW)) {
56.2605 + if ((decl = vars(TypeQual_None)) == NULL)
56.2606 + return NULL;
56.2607 + } else {
56.2608 + if ((decl = expressionStatement()) == NULL)
56.2609 + return NULL;
56.2610 + }
56.2611 + if (!expect(TOK_SEMICOLON))
56.2612 + return NULL;
56.2613 + }
56.2614 +
56.2615 + Expression *condition = NULL;
56.2616 + if (!match(TOK_SEMICOLON)) {
56.2617 + if ((condition = expression()) == NULL)
56.2618 + return NULL;
56.2619 + if (!expect(TOK_SEMICOLON))
56.2620 + return NULL;
56.2621 + }
56.2622 +
56.2623 + Statement *update = NULL;
56.2624 + if (!match(TOK_RPAREN)) {
56.2625 + if ((update = expressionStatement()) == NULL)
56.2626 + return NULL;
56.2627 + if (!expect(TOK_RPAREN))
56.2628 + return NULL;
56.2629 + }
56.2630 +
56.2631 + Statement *body;
56.2632 + if (scanner_.peek() == TOK_LBRACE)
56.2633 + body = block();
56.2634 + else
56.2635 + body = localStatement();
56.2636 + if (!body)
56.2637 + return NULL;
56.2638 +
56.2639 + return new (pool_) ForStatement(pos, decl, condition, update, body);
56.2640 +}
56.2641 +
56.2642 +ExpressionList *
56.2643 +Parser::dimensions()
56.2644 +{
56.2645 + // dimensions ::= ("[" expr? "]")*
56.2646 +
56.2647 + ExpressionList *postDimensions = new (pool_) ExpressionList();
56.2648 + while (match(TOK_LBRACKET)) {
56.2649 + Expression *dim = NULL;
56.2650 + if (!match(TOK_RBRACKET)) {
56.2651 + if ((dim = expression()) == NULL)
56.2652 + return NULL;
56.2653 + if (!expect(TOK_RBRACKET))
56.2654 + return NULL;
56.2655 + }
56.2656 +
56.2657 + if (!postDimensions->append(dim))
56.2658 + return NULL;
56.2659 + }
56.2660 + return postDimensions;
56.2661 +}
56.2662 +
56.2663 +VariableDeclaration *
56.2664 +Parser::var(TypeQualifiers qual)
56.2665 +{
56.2666 + // vardecl ::= decl ("=" expr)?
56.2667 +
56.2668 + Expression *type;
56.2669 + Local<String> name(zone_);
56.2670 +
56.2671 + if (!typeAndName(&type, name.ref()))
56.2672 + return NULL;
56.2673 +
56.2674 + ExpressionList *dims = NULL;
56.2675 + if (peek(TOK_LBRACKET)) {
56.2676 + if ((dims = dimensions()) == NULL)
56.2677 + return NULL;;
56.2678 + }
56.2679 +
56.2680 + SourcePosition pos = scanner_.begin();
56.2681 +
56.2682 + Expression *expr = NULL;
56.2683 + if (match(TOK_ASSIGN)) {
56.2684 + switch (scanner_.peek()) {
56.2685 + // Note: we don't support [] literals yet.
56.2686 + case TOK_LBRACE:
56.2687 + scanner_.scan();
56.2688 + if ((expr = fixedArrayLiteral()) == NULL)
56.2689 + return NULL;
56.2690 + break;
56.2691 +
56.2692 + default:
56.2693 + if ((expr = expression()) == NULL)
56.2694 + return NULL;
56.2695 + break;
56.2696 + }
56.2697 + }
56.2698 +
56.2699 + return new (pool_) VariableDeclaration(pos, qual, name, type, dims, expr);
56.2700 +}
56.2701 +
56.2702 +Statement *
56.2703 +Parser::vars(TypeQualifiers qual)
56.2704 +{
56.2705 + // localvars ::= ("new" | "const" | "decl") vardecl ("," vardecl)*
56.2706 + // globalvars ::= ("public" | "const" | "new" | "public" "const") vardecl
56.2707 + VariableDeclaration *decl = var(qual);
56.2708 + if (!decl)
56.2709 + return NULL;
56.2710 +
56.2711 + if (!peek(TOK_COMMA))
56.2712 + return decl;
56.2713 +
56.2714 + StatementList *statements = new (pool_) StatementList();
56.2715 + if (!statements->append(decl))
56.2716 + return NULL;
56.2717 +
56.2718 + while (match(TOK_COMMA)) {
56.2719 + Statement *decl = var(qual);
56.2720 + if (!decl)
56.2721 + return NULL;
56.2722 + if (!statements->append(decl))
56.2723 + return NULL;
56.2724 + }
56.2725 +
56.2726 + // Create a fake-o block with no scope to create a statement list.
56.2727 + return new (pool_) BlockStatement(decl->pos(), statements, TOK_NEW);
56.2728 +}
56.2729 +
56.2730 +Statement *
56.2731 +Parser::returnStatement()
56.2732 +{
56.2733 + // return ::= "return" term |
56.2734 + // "return" "expr"
56.2735 +
56.2736 + SourcePosition pos = scanner_.begin();
56.2737 + if (!expect(TOK_RETURN))
56.2738 + return NULL;
56.2739 +
56.2740 + Expression *expr = NULL;
56.2741 + if (scanner_.peek() != TOK_SEMICOLON) {
56.2742 + if ((expr = expression()) == NULL)
56.2743 + return NULL;
56.2744 +
56.2745 + // We only care about non-void returns when determining whether a
56.2746 + // tagless function is non-void.
56.2747 + encounteredReturn_ = true;
56.2748 + }
56.2749 +
56.2750 + return new (pool_) ReturnStatement(pos, expr);
56.2751 +}
56.2752 +
56.2753 +Statement *
56.2754 +Parser::expressionStatement()
56.2755 +{
56.2756 + // exprstmt ::= expr
56.2757 + Expression *left = assignment();
56.2758 + if (!left)
56.2759 + return NULL;
56.2760 +
56.2761 + return new (pool_) ExpressionStatement(left);
56.2762 +}
56.2763 +
56.2764 +Statement *
56.2765 +Parser::block()
56.2766 +{
56.2767 + // block ::= "{" statement* "}"
56.2768 +
56.2769 + if (!expect(TOK_LBRACE))
56.2770 + return NULL;
56.2771 +
56.2772 + SourcePosition pos = scanner_.begin();
56.2773 +
56.2774 + StatementList *statements = new (pool_) StatementList();
56.2775 + while (!match(TOK_RBRACE)) {
56.2776 + Statement *statement = localStatement();
56.2777 + if (statement == NULL)
56.2778 + return NULL;
56.2779 + if (!statements->append(statement))
56.2780 + return NULL;
56.2781 + }
56.2782 +
56.2783 + BlockStatement *block = new (pool_) BlockStatement(pos, statements, TOK_LBRACE);
56.2784 + return block;
56.2785 +}
56.2786 +
56.2787 +Statement *
56.2788 +Parser::if_()
56.2789 +{
56.2790 + // if ::= "if" "(" expr ")" statement elseif* else?
56.2791 + // elseif ::= "elseif" "(" expr ")" statement
56.2792 + // else ::= "else" statement
56.2793 + expect(TOK_IF);
56.2794 +
56.2795 + SourcePosition pos = scanner_.begin();
56.2796 + if (!expect(TOK_LPAREN))
56.2797 + return NULL;
56.2798 +
56.2799 + Expression *cond = expression();
56.2800 + if (!cond)
56.2801 + return NULL;
56.2802 +
56.2803 + if (!expect(TOK_RPAREN))
56.2804 + return NULL;
56.2805 +
56.2806 + Statement *ifTrue = localStatement();
56.2807 + if (!ifTrue)
56.2808 + return NULL;
56.2809 +
56.2810 + IfStatement *outer = new (pool_) IfStatement(pos, cond, ifTrue);
56.2811 +
56.2812 + IfStatement *last = outer;
56.2813 + while (match(TOK_ELSE)) {
56.2814 + if (!match(TOK_IF)) {
56.2815 + Statement *ifFalse = localStatement();
56.2816 + if (!ifFalse)
56.2817 + return NULL;
56.2818 +
56.2819 + last->setIfFalse(ifFalse);
56.2820 + break;
56.2821 + }
56.2822 +
56.2823 + SourcePosition pos = scanner_.begin();
56.2824 + if (!expect(TOK_LPAREN))
56.2825 + return NULL;
56.2826 +
56.2827 + Expression *otherCond = expression();
56.2828 + if (!otherCond)
56.2829 + return NULL;
56.2830 +
56.2831 + if (!expect(TOK_RPAREN))
56.2832 + return NULL;
56.2833 +
56.2834 + Statement *otherIfTrue = localStatement();
56.2835 + if (!otherIfTrue)
56.2836 + return NULL;
56.2837 +
56.2838 + IfStatement *inner = new (pool_) IfStatement(pos, otherCond, otherIfTrue);
56.2839 + last->setIfFalse(inner);
56.2840 + last = inner;
56.2841 + }
56.2842 +
56.2843 + return outer;
56.2844 +}
56.2845 +
56.2846 +Statement *
56.2847 +Parser::localStatement()
56.2848 +{
56.2849 + // statement ::= stmt term
56.2850 + // stmt ::= do | for | if | while | struct | enum |
56.2851 + // localvars | return | switch | break | continue
56.2852 +
56.2853 + Statement *statement = NULL;
56.2854 +
56.2855 + // Statements which must be followed by a semicolon will break out of the
56.2856 + // switch. If they may end in BlockStatements, they'll immediately return.
56.2857 +
56.2858 + TokenKind kind = scanner_.peek();
56.2859 + switch (kind) {
56.2860 + case TOK_CONST:
56.2861 + case TOK_NEW:
56.2862 + {
56.2863 + TypeQualifiers quals = (kind == TOK_CONST)
56.2864 + ? TypeQual_Const
56.2865 + : TypeQual_None;
56.2866 + scanner_.scan();
56.2867 + if ((statement = vars(quals)) == NULL)
56.2868 + return NULL;
56.2869 + break;
56.2870 + }
56.2871 +
56.2872 + case TOK_FOR:
56.2873 + return forStatement();
56.2874 +
56.2875 + case TOK_WHILE:
56.2876 + return while_();
56.2877 +
56.2878 + case TOK_BREAK:
56.2879 + scanner_.scan();
56.2880 + statement = new (pool_) BreakStatement(scanner_.begin());
56.2881 + break;
56.2882 +
56.2883 + case TOK_CONTINUE:
56.2884 + scanner_.scan();
56.2885 + statement = new (pool_) ContinueStatement(scanner_.begin());
56.2886 + break;
56.2887 +
56.2888 + case TOK_DO:
56.2889 + if ((statement = do_()) == NULL)
56.2890 + return NULL;
56.2891 + break;
56.2892 +
56.2893 + case TOK_RETURN:
56.2894 + if ((statement = returnStatement()) == NULL)
56.2895 + return NULL;
56.2896 + break;
56.2897 +
56.2898 + case TOK_ENUM:
56.2899 + if ((statement = enum_(TOK_NONE)) == NULL)
56.2900 + return NULL;
56.2901 + break;
56.2902 +
56.2903 + case TOK_STRUCT:
56.2904 + if ((statement = struct_()) == NULL)
56.2905 + return NULL;
56.2906 + break;
56.2907 +
56.2908 + case TOK_SWITCH:
56.2909 + return switch_();
56.2910 +
56.2911 + case TOK_IF:
56.2912 + return if_();
56.2913 +
56.2914 + case TOK_LBRACE:
56.2915 + return block();
56.2916 +
56.2917 + default:
56.2918 + break;
56.2919 + }
56.2920 +
56.2921 + if (!statement) {
56.2922 + if ((statement = expressionStatement()) == NULL)
56.2923 + return NULL;
56.2924 + }
56.2925 +
56.2926 + if (!expect(TOK_SEMICOLON))
56.2927 + return NULL;
56.2928 +
56.2929 + return statement;
56.2930 +}
56.2931 +
56.2932 +Statement *
56.2933 +Parser::struct_()
56.2934 +{
56.2935 + // struct ::= "struct" name { struct_fields }
56.2936 + // struct_fields ::= struct_field |
56.2937 + // struct_field struct_fields
56.2938 + // struct_field ::= label? name term
56.2939 + expect(TOK_STRUCT);
56.2940 +
56.2941 + Local<String> name(zone_, expectName());
56.2942 + if (!name)
56.2943 + return NULL;
56.2944 +
56.2945 + SourcePosition pos = scanner_.begin();
56.2946 +
56.2947 + if (!expect(TOK_LBRACE))
56.2948 + return NULL;
56.2949 +
56.2950 + FieldList *fields = new (pool_) FieldList();
56.2951 +
56.2952 + while (!peek(TOK_RBRACE)) {
56.2953 + Expression *type;
56.2954 + Local<String> fieldName(zone_);
56.2955 +
56.2956 + if (!fullTypeAndName(&type, fieldName.ref(), DeclField))
56.2957 + return NULL;
56.2958 +
56.2959 + SourcePosition pos = scanner_.begin();
56.2960 +
56.2961 + if (!matchSemicolon())
56.2962 + return NULL;
56.2963 +
56.2964 + StructureStatement::Field *field =
56.2965 + new (pool_) StructureStatement::Field(pos, type, fieldName);
56.2966 + if (!field || !fields->append(field))
56.2967 + return NULL;
56.2968 + }
56.2969 +
56.2970 + if (!expect(TOK_RBRACE))
56.2971 + return NULL;
56.2972 +
56.2973 + if (fields->empty()) {
56.2974 + cc_.reportError(pos, Message_StructCantBeEmpty);
56.2975 + return NULL;
56.2976 + }
56.2977 +
56.2978 + return new (pool_) StructureStatement(pos, name, fields);
56.2979 +}
56.2980 +
56.2981 +Statement *
56.2982 +Parser::enum_(TokenKind kind)
56.2983 +{
56.2984 + // enum ::= "enum" name? { enum_members? }
56.2985 + // enum_members ::= enum_member ","? |
56.2986 + // enum_member "," enum_members
56.2987 + // enum_member ::= ident ("=" constexpr)?
56.2988 + expect(TOK_ENUM);
56.2989 +
56.2990 + SourcePosition pos = scanner_.begin();
56.2991 +
56.2992 + Local<String> name(zone_);
56.2993 + if (matchName(name.ref()) && !name)
56.2994 + return NULL;
56.2995 +
56.2996 + EnumStatement::EntryList *entries = new (pool_) EnumStatement::EntryList();
56.2997 +
56.2998 + if (!expect(TOK_LBRACE))
56.2999 + return NULL;
56.3000 +
56.3001 + do {
56.3002 + if (scanner_.peek() == TOK_RBRACE)
56.3003 + break;
56.3004 +
56.3005 + SourcePosition pos = scanner_.begin();
56.3006 + Local<String> name(zone_, expectName());
56.3007 + if (!name)
56.3008 + return NULL;
56.3009 +
56.3010 + Expression *expr = NULL;
56.3011 + if (match(TOK_ASSIGN)) {
56.3012 + if ((expr = expression()) == NULL)
56.3013 + return NULL;
56.3014 + }
56.3015 +
56.3016 + if (!entries->append(EnumStatement::Entry(name, expr, pos)))
56.3017 + return NULL;
56.3018 + } while (match(TOK_COMMA));
56.3019 + if (!expect(TOK_RBRACE))
56.3020 + return NULL;
56.3021 +
56.3022 + return new (pool_) EnumStatement(pos, kind, name, entries);
56.3023 +}
56.3024 +
56.3025 +template <class T>
56.3026 +static inline ScopedRoot<T> *
56.3027 +NewScopedRoot(PoolAllocator &pool, Handle<T> obj)
56.3028 +{
56.3029 + return new (pool) ScopedRoot<T>(obj);
56.3030 +}
56.3031 +
56.3032 +ImportStatement *
56.3033 +Parser::import(TokenKind kind)
56.3034 +{
56.3035 + SourcePosition pos = scanner_.begin();
56.3036 +
56.3037 + // import ::= "from" import_path "import" import_names
56.3038 + // | "import" import_path
56.3039 + // | "import" import_path ".*"
56.3040 + // import_path ::= name
56.3041 + // | name "." import_path
56.3042 + // import_names ::= "*"
56.3043 + // | import_name_list
56.3044 + // import_name_list ::= name
56.3045 + // | name "," import_name_list
56.3046 +
56.3047 + Local<String> name(zone_, expectName());
56.3048 + if (!name)
56.3049 + return NULL;
56.3050 +
56.3051 + PathComponent *root = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
56.3052 + PathComponent *current = root;
56.3053 +
56.3054 + // NULL namelist means that we do not import any names. An empty namelist
56.3055 + // means we import all names.
56.3056 + NameList *names = NULL;
56.3057 +
56.3058 + while (match(TOK_DOT)) {
56.3059 + if (kind == TOK_IMPORT && match(TOK_STAR)) {
56.3060 + names = new (pool_) NameList();
56.3061 + break;
56.3062 + }
56.3063 +
56.3064 + if ((name = expectName()) == NULL)
56.3065 + return NULL;
56.3066 +
56.3067 + current->next = new (pool_) PathComponent(NewScopedRoot<String>(pool_, name), NULL);
56.3068 + current = current->next;
56.3069 + }
56.3070 +
56.3071 + if (kind == TOK_FROM) {
56.3072 + if (!expect(TOK_IMPORT))
56.3073 + return NULL;
56.3074 +
56.3075 + names = new (pool_) NameList();
56.3076 +
56.3077 + if (!match(TOK_STAR)) {
56.3078 + if (!matchName(name.address())) {
56.3079 + cc_.reportError(scanner_.begin(), Message_BadImportFrom);
56.3080 + return NULL;
56.3081 + }
56.3082 +
56.3083 + if (!name || !names->append(NewScopedRoot<String>(pool_, name)))
56.3084 + return NULL;
56.3085 +
56.3086 + while (match(TOK_COMMA)) {
56.3087 + if ((name = expectName()) == NULL)
56.3088 + return NULL;
56.3089 + if (!names->append(NewScopedRoot<String>(pool_, name)))
56.3090 + return NULL;
56.3091 + }
56.3092 + }
56.3093 + }
56.3094 +
56.3095 + return new (pool_) ImportStatement(pos, root, names);
56.3096 +}
56.3097 +
56.3098 +Statement *
56.3099 +Parser::function(TokenKind token)
56.3100 +{
56.3101 + Expression *returnType;
56.3102 + Local<String> name(zone_);
56.3103 +
56.3104 + if (!fullTypeAndName(&returnType, name.ref(), DeclFun))
56.3105 + return NULL;
56.3106 +
56.3107 + SourcePosition pos = scanner_.begin();
56.3108 + ParameterList *parameters = new (pool_) ParameterList();
56.3109 +
56.3110 + if (!expect(TOK_LPAREN))
56.3111 + return NULL;
56.3112 +
56.3113 + bool variadic = false;
56.3114 +
56.3115 + if (!match(TOK_RPAREN)) {
56.3116 + while (true) {
56.3117 + TypeQualifiers quals = TypeQual_None;
56.3118 + if (match(TOK_CONST))
56.3119 + quals = TypeQualifiers(quals | TypeQual_Const);
56.3120 +
56.3121 + bool ref = match(TOK_AMPERSAND);
56.3122 +
56.3123 + SourcePosition begin = scanner_.begin();
56.3124 + Expression *type;
56.3125 + Local<String> name(zone_);
56.3126 + if (!fullTypeAndName(&type, name.ref(), DeclArg))
56.3127 + return NULL;
56.3128 +
56.3129 + if (!name) {
56.3130 + if ((quals & TypeQual_Const) || ref) {
56.3131 + cc_.reportError(begin, Message_InvalidVarArgs);
56.3132 + return NULL;
56.3133 + }
56.3134 +
56.3135 + if (token != TOK_NATIVE) {
56.3136 + cc_.reportError(begin, Message_VarArgsOutsideNative);
56.3137 + return NULL;
56.3138 + }
56.3139 +
56.3140 + variadic = true;
56.3141 + break;
56.3142 + }
56.3143 +
56.3144 + ExpressionList *dims = NULL;
56.3145 + if (peek(TOK_LBRACKET)) {
56.3146 + if ((dims = dimensions()) == NULL)
56.3147 + return NULL;
56.3148 + }
56.3149 +
56.3150 + Expression *expr = NULL;
56.3151 + if (match(TOK_ASSIGN)) {
56.3152 + if ((expr = expression()) == NULL)
56.3153 + return NULL;
56.3154 + }
56.3155 +
56.3156 + Parameter *parameter = new (pool_) Parameter(name, type, ref, quals, dims, expr, begin);
56.3157 + if (!parameters->append(parameter))
56.3158 + return NULL;
56.3159 +
56.3160 + if (!match(TOK_COMMA))
56.3161 + break;
56.3162 + }
56.3163 + if (!expect(TOK_RPAREN))
56.3164 + return NULL;
56.3165 + }
56.3166 +
56.3167 + encounteredReturn_ = false;
56.3168 +
56.3169 + Statement *body = NULL;
56.3170 + if (token != TOK_FORWARD && token != TOK_NATIVE && token != TOK_TYPEDEF) {
56.3171 + body = block();
56.3172 + if (!body)
56.3173 + return NULL;
56.3174 + }
56.3175 +
56.3176 + FunctionSignature signature(returnType, parameters, variadic);
56.3177 + if (token == TOK_TYPEDEF)
56.3178 + return new (pool_) FunctionTypeStatement(pos, name, signature);
56.3179 +
56.3180 + return new (pool_) FunctionStatement(pos, name, token, body, signature, encounteredReturn_);
56.3181 +}
56.3182 +
56.3183 +static inline bool
56.3184 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, Handle<Type> type)
56.3185 +{
56.3186 + Local<String> tag(zone, zone->makeSymbol(name));
56.3187 + if (!tag)
56.3188 + return false;
56.3189 +
56.3190 + assert(false);
56.3191 + return false; //return !!scope->declareType(tag, type);
56.3192 +}
56.3193 +
56.3194 +static inline bool
56.3195 +DeclareIntrinsicType(Zone *zone, Scope *scope, const char *name, PrimitiveType type)
56.3196 +{
56.3197 + Local<Type> primitive(zone, zone->types()->getPrimitive(type));
56.3198 + assert(primitive);
56.3199 + return DeclareIntrinsicType(zone, scope, name, primitive);
56.3200 +}
56.3201 +
56.3202 +ParseTree *
56.3203 +Parser::parse()
56.3204 +{
56.3205 + StatementList *statements = new (pool_) StatementList();
56.3206 +
56.3207 + for (;;) {
56.3208 + Statement *statement = NULL;
56.3209 +
56.3210 + TokenKind kind = scanner_.peek();
56.3211 + switch (kind) {
56.3212 + case TOK_ERROR:
56.3213 + return NULL;
56.3214 +
56.3215 + case TOK_EOF:
56.3216 + break;
56.3217 +
56.3218 + case TOK_NAME:
56.3219 + if ((statement = function(TOK_NAME)) == NULL)
56.3220 + return NULL;
56.3221 + break;
56.3222 +
56.3223 + case TOK_FROM:
56.3224 + case TOK_IMPORT:
56.3225 + {
56.3226 + scanner_.scan();
56.3227 + if (statements->length())
56.3228 + cc_.reportError(scanner_.begin(), Message_ImportsMustBeFirst);
56.3229 + ImportStatement *stmt = import(kind);
56.3230 + if (!stmt)
56.3231 + return NULL;
56.3232 + if (!imports_->append(stmt))
56.3233 + return NULL;
56.3234 + if (!matchSemicolon())
56.3235 + return NULL;
56.3236 + continue;
56.3237 + }
56.3238 +
56.3239 + case TOK_FORWARD:
56.3240 + case TOK_PUBLIC:
56.3241 + case TOK_NATIVE:
56.3242 + case TOK_STOCK:
56.3243 + case TOK_LABEL:
56.3244 + case TOK_TYPEDEF:
56.3245 + {
56.3246 + if (kind != TOK_LABEL)
56.3247 + scanner_.scan();
56.3248 + if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
56.3249 + if ((statement = var(TypeQual_Const)) == NULL)
56.3250 + return NULL;
56.3251 + if (!matchSemicolon())
56.3252 + return NULL;
56.3253 + } else if (kind == TOK_PUBLIC && peek(TOK_ENUM)) {
56.3254 + if ((statement = enum_(kind)) == NULL)
56.3255 + return NULL;
56.3256 + if (!matchSemicolon())
56.3257 + return NULL;
56.3258 + } else {
56.3259 + if ((statement = function(kind)) == NULL)
56.3260 + return NULL;
56.3261 + if ((kind == TOK_FORWARD || kind == TOK_NATIVE || kind == TOK_TYPEDEF) && !matchSemicolon())
56.3262 + return NULL;
56.3263 + }
56.3264 + break;
56.3265 + }
56.3266 +
56.3267 + case TOK_CONST:
56.3268 + case TOK_NEW:
56.3269 + {
56.3270 + TypeQualifiers quals = (kind == TOK_CONST) ? TypeQual_Const : TypeQual_None;
56.3271 + // Note: at global scope, we don't accept comma-delimited
56.3272 + // declarations yet, to see if we can get away with forcing
56.3273 + // a nicer top-level style.
56.3274 + scanner_.scan();
56.3275 + if ((statement = var(quals)) == NULL)
56.3276 + return NULL;
56.3277 + if (!matchSemicolon())
56.3278 + return NULL;
56.3279 + break;
56.3280 + }
56.3281 +
56.3282 + case TOK_ENUM:
56.3283 + if ((statement = enum_(TOK_NONE)) == NULL)
56.3284 + return NULL;
56.3285 + if (!matchSemicolon())
56.3286 + return NULL;
56.3287 + break;
56.3288 +
56.3289 + case TOK_STRUCT:
56.3290 + if ((statement = struct_()) == NULL)
56.3291 + return NULL;
56.3292 + if (!matchSemicolon())
56.3293 + return NULL;
56.3294 + break;
56.3295 +
56.3296 + default:
56.3297 + cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
56.3298 + return NULL;
56.3299 + }
56.3300 +
56.3301 + if (!statement)
56.3302 + break;
56.3303 +
56.3304 + if (!statements->append(statement))
56.3305 + return NULL;
56.3306 + }
56.3307 +
56.3308 + return new (pool_) ParseTree(statements, unbound_, imports_);
56.3309 +}
56.3310 +
56.3311 +class AstPrinter : public AstVisitor
56.3312 +{
56.3313 + FILE *fp_;
56.3314 + size_t level_;
56.3315 +
56.3316 + private:
56.3317 + void prefix() {
56.3318 + for (size_t i = 0; i < level_; i++)
56.3319 + fprintf(fp_, " ");
56.3320 + }
56.3321 + void indent() {
56.3322 + level_++;
56.3323 + }
56.3324 + void unindent() {
56.3325 + level_--;
56.3326 + }
56.3327 +
56.3328 + public:
56.3329 + AstPrinter(FILE *fp)
56.3330 + : fp_(fp),
56.3331 + level_(0)
56.3332 + {
56.3333 + }
56.3334 +
56.3335 + void dump(const FunctionSignature &sig) {
56.3336 + prefix();
56.3337 + fprintf(fp_, "()\n");
56.3338 + }
56.3339 + void visitNameProxy(NameProxy *name) {
56.3340 + prefix();
56.3341 + fprintf(fp_, "[ NameProxy (%s)\n", name->name()->chars());
56.3342 + }
56.3343 + void visitCallExpression(CallExpression *node) {
56.3344 + prefix();
56.3345 + fprintf(fp_, "[ CallExpression\n");
56.3346 + indent();
56.3347 + node->callee()->accept(this);
56.3348 + for (size_t i = 0; i < node->arguments()->length(); i++)
56.3349 + node->arguments()->at(i)->accept(this);
56.3350 + unindent();
56.3351 + }
56.3352 + void visitFunctionTypeStatement(FunctionTypeStatement *node) {
56.3353 + prefix();
56.3354 + fprintf(fp_, "[ FunctionTypeStatement (%s)\n", node->name()->chars());
56.3355 + indent();
56.3356 + dump(node->signature());
56.3357 + unindent();
56.3358 + }
56.3359 + void visitFunctionStatement(FunctionStatement *node) {
56.3360 + prefix();
56.3361 + fprintf(fp_, "[ FunctionStatement (%s)\n", node->name()->chars());
56.3362 + indent();
56.3363 + dump(node->signature());
56.3364 + if (node->body())
56.3365 + node->body()->accept(this);
56.3366 + unindent();
56.3367 + }
56.3368 + void visitExpressionStatement(ExpressionStatement *node) {
56.3369 + prefix();
56.3370 + fprintf(fp_, "[ ExpressionStatement\n");
56.3371 + indent();
56.3372 + node->expression()->accept(this);
56.3373 + unindent();
56.3374 + }
56.3375 + void visitAssignment(Assignment *node) {
56.3376 + prefix();
56.3377 + fprintf(fp_, "[ Assignment\n");
56.3378 + indent();
56.3379 + node->lvalue()->accept(this);
56.3380 + node->expression()->accept(this);
56.3381 + unindent();
56.3382 + }
56.3383 + void visitTernaryExpression(TernaryExpression *node) {
56.3384 + prefix();
56.3385 + fprintf(fp_, "[ TernaryExpression\n");
56.3386 + indent();
56.3387 + node->condition()->accept(this);
56.3388 + node->left()->accept(this);
56.3389 + node->right()->accept(this);
56.3390 + unindent();
56.3391 + }
56.3392 + void visitBinaryExpression(BinaryExpression *node) {
56.3393 + prefix();
56.3394 + fprintf(fp_, "[ BinaryExpression (%s)\n", TokenNames[node->token()]);
56.3395 + indent();
56.3396 + node->left()->accept(this);
56.3397 + node->right()->accept(this);
56.3398 + unindent();
56.3399 + }
56.3400 + void visitUnaryExpression(UnaryExpression *node) {
56.3401 + prefix();
56.3402 + fprintf(fp_, "[ UnaryExpression (%s)\n", TokenNames[node->token()]);
56.3403 + indent();
56.3404 + node->expression()->accept(this);
56.3405 + unindent();
56.3406 + }
56.3407 + void visitReturnStatement(ReturnStatement *node) {
56.3408 + prefix();
56.3409 + fprintf(fp_, "[ ReturnStatement\n");
56.3410 + indent();
56.3411 + if (node->expression())
56.3412 + node->expression()->accept(this);
56.3413 + unindent();
56.3414 + }
56.3415 + void visitForStatement(ForStatement *node) {
56.3416 + prefix();
56.3417 + fprintf(fp_, "[ ForStatement\n");
56.3418 + indent();
56.3419 + if (node->initialization())
56.3420 + node->initialization()->accept(this);
56.3421 + if (node->condition())
56.3422 + node->condition()->accept(this);
56.3423 + if (node->update())
56.3424 + node->update()->accept(this);
56.3425 + node->body()->accept(this);
56.3426 + unindent();
56.3427 + }
56.3428 + void visitBlockStatement(BlockStatement *node) {
56.3429 + prefix();
56.3430 + fprintf(fp_, "[ BlockStatement\n");
56.3431 + indent();
56.3432 + for (size_t i = 0; i < node->statements()->length(); i++)
56.3433 + node->statements()->at(i)->accept(this);
56.3434 + unindent();
56.3435 + }
56.3436 + void visitVariableDeclaration(VariableDeclaration *node) {
56.3437 + prefix();
56.3438 + fprintf(fp_, "[ VariableDeclaration (%s)\n", node->name()->chars());
56.3439 + indent();
56.3440 + if (node->initialization())
56.3441 + node->initialization()->accept(this);
56.3442 + unindent();
56.3443 + }
56.3444 + void visitIntegerLiteral(IntegerLiteral *node) {
56.3445 + prefix();
56.3446 + fprintf(fp_, "[ IntegerLiteral (%d)\n", node->value());
56.3447 + }
56.3448 + void visitBooleanLiteral(BooleanLiteral *node) {
56.3449 + prefix();
56.3450 + fprintf(fp_, "[ BooleanLiteral (%s)\n",
56.3451 + (node->token() == TOK_TRUE) ? "true" : "false");
56.3452 + }
56.3453 + void visitFloatLiteral(FloatLiteral *node) {
56.3454 + prefix();
56.3455 + fprintf(fp_, "[ FloatLiteral (%f)\n", node->value());
56.3456 + }
56.3457 + void visitIfStatement(IfStatement *node) {
56.3458 + prefix();
56.3459 + fprintf(fp_, "[ IfStatement\n");
56.3460 + indent();
56.3461 + node->ifTrue()->accept(this);
56.3462 + if (node->ifFalse())
56.3463 + node->ifFalse()->accept(this);
56.3464 + unindent();
56.3465 + }
56.3466 + void visitIndexExpression(IndexExpression *node) {
56.3467 + prefix();
56.3468 + fprintf(fp_, "[ IndexExpression\n");
56.3469 + indent();
56.3470 + node->left()->accept(this);
56.3471 + node->right()->accept(this);
56.3472 + unindent();
56.3473 + }
56.3474 + void visitEnumStatement(EnumStatement *node) {
56.3475 + prefix();
56.3476 + fprintf(fp_, "[ EnumStatement (%s)\n", node->name() ? node->name()->chars() : "<anonymous>");
56.3477 + indent();
56.3478 + for (size_t i = 0; i < node->entries()->length(); i++) {
56.3479 + prefix();
56.3480 + fprintf(fp_, "%s =\n", node->entries()->at(i).name->chars());
56.3481 + if (node->entries()->at(i).expr) {
56.3482 + indent();
56.3483 + node->entries()->at(i).expr->accept(this);
56.3484 + unindent();
56.3485 + }
56.3486 + }
56.3487 + unindent();
56.3488 + }
56.3489 + void visitWhileStatement(WhileStatement *node) {
56.3490 + prefix();
56.3491 + fprintf(fp_, "[ WhileStatement (%s)\n",
56.3492 + (node->token() == TOK_DO) ? "do" : "while");
56.3493 + indent();
56.3494 + if (node->token() == TOK_DO) {
56.3495 + node->condition()->accept(this);
56.3496 + node->body()->accept(this);
56.3497 + } else {
56.3498 + node->condition()->accept(this);
56.3499 + node->body()->accept(this);
56.3500 + }
56.3501 + unindent();
56.3502 + }
56.3503 + void visitBreakStatement(BreakStatement *node) {
56.3504 + prefix();
56.3505 + fprintf(fp_, "[ BreakStatement\n");
56.3506 + }
56.3507 + void visitContinueStatement(ContinueStatement *node) {
56.3508 + prefix();
56.3509 + fprintf(fp_, "[ ContinueStatement\n");
56.3510 + }
56.3511 + void visitStringLiteral(StringLiteral *node) {
56.3512 + prefix();
56.3513 + fprintf(fp_, "[ StringLiteral\n");
56.3514 + }
56.3515 + void visitIncDecExpression(IncDecExpression *node) {
56.3516 + prefix();
56.3517 + fprintf(fp_, "[ IncDecExpression (postfix=%d)\n", node->postfix());
56.3518 + indent();
56.3519 + node->expression()->accept(this);
56.3520 + unindent();
56.3521 + }
56.3522 + void visitStructureStatement(StructureStatement *node) {
56.3523 + prefix();
56.3524 + fprintf(fp_, "[ StructureStatement %s\n", node->name()->chars());
56.3525 + }
56.3526 + void visitFieldExpression(FieldExpression *node) {
56.3527 + prefix();
56.3528 + fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
56.3529 + indent();
56.3530 + node->left()->accept(this);
56.3531 + unindent();
56.3532 + }
56.3533 + void visitSwitchStatement(SwitchStatement *node) {
56.3534 + prefix();
56.3535 + fprintf(fp_, "[ SwitchStatement\n");
56.3536 + indent();
56.3537 + node->expression()->accept(this);
56.3538 + for (size_t i = 0; i < node->cases()->length(); i++) {
56.3539 + Case *c = node->cases()->at(i);
56.3540 + c->expression()->accept(this);
56.3541 + if (c->others()) {
56.3542 + for (size_t j = 0; j < c->others()->length(); j++)
56.3543 + c->others()->at(j)->accept(this);
56.3544 + }
56.3545 + indent();
56.3546 + c->statement()->accept(this);
56.3547 + unindent();
56.3548 + }
56.3549 + if (node->defaultCase())
56.3550 + node->defaultCase()->accept(this);
56.3551 + unindent();
56.3552 + }
56.3553 + void visitArrayLiteral(ArrayLiteral *node) {
56.3554 + prefix();
56.3555 + fprintf(fp_, "[ ArrayLiteral\n");
56.3556 + indent();
56.3557 + for (size_t i = 0; i < node->expressions()->length(); i++) {
56.3558 + Expression *expr = node->expressions()->at(i);
56.3559 + indent();
56.3560 + expr->accept(this);
56.3561 + unindent();
56.3562 + }
56.3563 + }
56.3564 + void visitImportStatement(ImportStatement *node) {
56.3565 + prefix();
56.3566 + fprintf(fp_, "[ ImportStatement\n");
56.3567 + }
56.3568 +};
56.3569 +
56.3570 +void
56.3571 +ParseTree::dump(FILE *fp)
56.3572 +{
56.3573 + AstPrinter printer(fp);
56.3574 +
56.3575 + for (size_t i = 0; i < statements_->length(); i++)
56.3576 + statements_->at(i)->accept(&printer);
56.3577 +}
57.1 --- a/src/compiler/Parser.h Mon Jun 10 00:46:29 2013 +0100
57.2 +++ b/src/compiler/Parser.h Mon Jun 10 01:04:43 2013 +0100
57.3 @@ -1,106 +1,106 @@
57.4 -/* vim: set ts=4 sw=4 tw=99 et:
57.5 - *
57.6 - * Copyright (C) 2012 David Anderson
57.7 - *
57.8 - * This file is part of SourcePawn.
57.9 - *
57.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
57.11 - * the terms of the GNU General Public License as published by the Free
57.12 - * Software Foundation, either version 3 of the License, or (at your option)
57.13 - * any later version.
57.14 - *
57.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
57.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
57.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
57.18 - *
57.19 - * You should have received a copy of the GNU General Public License along with
57.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
57.21 - */
57.22 -#ifndef _include_jitcraft_parser_h_
57.23 -#define _include_jitcraft_parser_h_
57.24 -
57.25 -#include <stdio.h>
57.26 -#include "../Strings.h"
57.27 -#include "AST.h"
57.28 -#include "Scanner.h"
57.29 -#include "Scopes.h"
57.30 -
57.31 -namespace ke {
57.32 -
57.33 -class Parser
57.34 -{
57.35 - Zone *zone_;
57.36 - CompileContext &cc_;
57.37 - PoolAllocator &pool_;
57.38 - Scanner scanner_;
57.39 - PoolList<NameProxy *> *unbound_;
57.40 - PoolList<ImportStatement *> *imports_;
57.41 - bool encounteredReturn_;
57.42 -
57.43 - private:
57.44 - bool peek(TokenKind kind);
57.45 - bool match(TokenKind kind);
57.46 - bool expect(TokenKind kind);
57.47 - bool matchSemicolon();
57.48 -
57.49 - enum DeclKind {
57.50 - DeclArg,
57.51 - DeclFun,
57.52 - DeclField
57.53 - };
57.54 -
57.55 - VariableDeclaration *var(TypeQualifiers qual);
57.56 - Statement *vars(TypeQualifiers qual);
57.57 - bool matchName(String **name, TokenKind kind = TOK_NAME);
57.58 - bool typeAndName(Expression **type, String **namep);
57.59 - bool fullTypeAndName(Expression **type, String **namep, DeclKind kind);
57.60 -
57.61 - ExpressionList *dimensions();
57.62 - String *expectName();
57.63 -
57.64 - Expression *primitive();
57.65 - Expression *fixedArrayLiteral();
57.66 - Expression *call(Expression *callee);
57.67 - Expression *field(Expression *left);
57.68 - Expression *index(Expression *left);
57.69 - Expression *prefix();
57.70 - Expression *primary();
57.71 - Expression *unary();
57.72 - Expression *multiplication();
57.73 - Expression *addition();
57.74 - Expression *shift();
57.75 - Expression *bitand_();
57.76 - Expression *bitxor();
57.77 - Expression *bitor_();
57.78 - Expression *relational();
57.79 - Expression *equals();
57.80 - Expression *and_();
57.81 - Expression *or_();
57.82 - Expression *ternary();
57.83 - Expression *assignment();
57.84 - Expression *expression();
57.85 -
57.86 - Statement *switch_();
57.87 - Statement *struct_();
57.88 - Statement *enum_(TokenKind kind);
57.89 - Statement *if_();
57.90 - Statement *block();
57.91 - Statement *function(TokenKind tok);
57.92 - Statement *expressionStatement();
57.93 - Statement *while_();
57.94 - Statement *do_();
57.95 - Statement *forStatement();
57.96 - Statement *localStatement();
57.97 - Statement *globalStatement();
57.98 - Statement *returnStatement();
57.99 - ImportStatement *import(TokenKind kind);
57.100 -
57.101 - public:
57.102 - Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
57.103 -
57.104 - ParseTree *parse();
57.105 -};
57.106 -
57.107 -}
57.108 -
57.109 -#endif // _include_jitcraft_parser_h_
57.110 +/* vim: set ts=4 sw=4 tw=99 et:
57.111 + *
57.112 + * Copyright (C) 2012 David Anderson
57.113 + *
57.114 + * This file is part of SourcePawn.
57.115 + *
57.116 + * SourcePawn is free software: you can redistribute it and/or modify it under
57.117 + * the terms of the GNU General Public License as published by the Free
57.118 + * Software Foundation, either version 3 of the License, or (at your option)
57.119 + * any later version.
57.120 + *
57.121 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
57.122 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
57.123 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
57.124 + *
57.125 + * You should have received a copy of the GNU General Public License along with
57.126 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
57.127 + */
57.128 +#ifndef _include_jitcraft_parser_h_
57.129 +#define _include_jitcraft_parser_h_
57.130 +
57.131 +#include <stdio.h>
57.132 +#include "../Strings.h"
57.133 +#include "AST.h"
57.134 +#include "Scanner.h"
57.135 +#include "Scopes.h"
57.136 +
57.137 +namespace ke {
57.138 +
57.139 +class Parser
57.140 +{
57.141 + Zone *zone_;
57.142 + CompileContext &cc_;
57.143 + PoolAllocator &pool_;
57.144 + Scanner scanner_;
57.145 + PoolList<NameProxy *> *unbound_;
57.146 + PoolList<ImportStatement *> *imports_;
57.147 + bool encounteredReturn_;
57.148 +
57.149 + private:
57.150 + bool peek(TokenKind kind);
57.151 + bool match(TokenKind kind);
57.152 + bool expect(TokenKind kind);
57.153 + bool matchSemicolon();
57.154 +
57.155 + enum DeclKind {
57.156 + DeclArg,
57.157 + DeclFun,
57.158 + DeclField
57.159 + };
57.160 +
57.161 + VariableDeclaration *var(TypeQualifiers qual);
57.162 + Statement *vars(TypeQualifiers qual);
57.163 + bool matchName(String **name, TokenKind kind = TOK_NAME);
57.164 + bool typeAndName(Expression **type, String **namep);
57.165 + bool fullTypeAndName(Expression **type, String **namep, DeclKind kind);
57.166 +
57.167 + ExpressionList *dimensions();
57.168 + String *expectName();
57.169 +
57.170 + Expression *primitive();
57.171 + Expression *fixedArrayLiteral();
57.172 + Expression *call(Expression *callee);
57.173 + Expression *field(Expression *left);
57.174 + Expression *index(Expression *left);
57.175 + Expression *prefix();
57.176 + Expression *primary();
57.177 + Expression *unary();
57.178 + Expression *multiplication();
57.179 + Expression *addition();
57.180 + Expression *shift();
57.181 + Expression *bitand_();
57.182 + Expression *bitxor();
57.183 + Expression *bitor_();
57.184 + Expression *relational();
57.185 + Expression *equals();
57.186 + Expression *and_();
57.187 + Expression *or_();
57.188 + Expression *ternary();
57.189 + Expression *assignment();
57.190 + Expression *expression();
57.191 +
57.192 + Statement *switch_();
57.193 + Statement *struct_();
57.194 + Statement *enum_(TokenKind kind);
57.195 + Statement *if_();
57.196 + Statement *block();
57.197 + Statement *function(TokenKind tok);
57.198 + Statement *expressionStatement();
57.199 + Statement *while_();
57.200 + Statement *do_();
57.201 + Statement *forStatement();
57.202 + Statement *localStatement();
57.203 + Statement *globalStatement();
57.204 + Statement *returnStatement();
57.205 + ImportStatement *import(TokenKind kind);
57.206 +
57.207 + public:
57.208 + Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
57.209 +
57.210 + ParseTree *parse();
57.211 +};
57.212 +
57.213 +}
57.214 +
57.215 +#endif // _include_jitcraft_parser_h_
58.1 --- a/src/compiler/Scanner.cpp Mon Jun 10 00:46:29 2013 +0100
58.2 +++ b/src/compiler/Scanner.cpp Mon Jun 10 01:04:43 2013 +0100
58.3 @@ -1,685 +1,685 @@
58.4 -/* vim: set ts=4 sw=4 tw=99 et:
58.5 - *
58.6 - * Copyright (C) 2012 David Anderson
58.7 - *
58.8 - * This file is part of JITCraft.
58.9 - *
58.10 - * JITCraft is free software: you can redistribute it and/or modify it under
58.11 - * the terms of the GNU General Public License as published by the Free
58.12 - * Software Foundation, either version 3 of the License, or (at your option)
58.13 - * any later version.
58.14 - *
58.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
58.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
58.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
58.18 - *
58.19 - * You should have received a copy of the GNU General Public License along with
58.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
58.21 - */
58.22 -#include <assert.h>
58.23 -#include <ctype.h>
58.24 -#include <math.h>
58.25 -#include <limits.h>
58.26 -#include <string.h>
58.27 -#include "../Utility.h"
58.28 -#include "../Heap-inl.h"
58.29 -#include "../Handles-inl.h"
58.30 -#include "Scanner.h"
58.31 -
58.32 -using namespace ke;
58.33 -
58.34 -const char *ke::TokenNames[] =
58.35 -{
58.36 -#define _(name, str) str,
58.37 - TOKENMAP(_)
58.38 -#undef _
58.39 - NULL
58.40 -};
58.41 -
58.42 -Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
58.43 - : cc_(cc),
58.44 - stream_(stream),
58.45 - length_(length),
58.46 - pushed_(false),
58.47 - allowTags_(true),
58.48 - saved_('\0'),
58.49 - pos_(stream_)
58.50 -{
58.51 - cur_.line = 1;
58.52 - cur_.col = 1;
58.53 - last_ = cur_;
58.54 -}
58.55 -
58.56 -char
58.57 -Scanner::getChar()
58.58 -{
58.59 - if (saved_ != '\0') {
58.60 - char temp = saved_;
58.61 - saved_ = '\0';
58.62 - return temp;
58.63 - }
58.64 - if (pos_ >= stream_ + length_)
58.65 - return '\0';
58.66 - last_.col = cur_.col++;
58.67 - return *pos_++;
58.68 -}
58.69 -
58.70 -void
58.71 -Scanner::putChar(char c)
58.72 -{
58.73 - assert(saved_ == '\0');
58.74 - saved_ = c;
58.75 - cur_.col = last_.col;
58.76 -}
58.77 -
58.78 -void
58.79 -Scanner::calcNewLine(char c)
58.80 -{
58.81 - cur_.line++;
58.82 - cur_.col = 1;
58.83 - last_ = cur_;
58.84 -
58.85 - char o;
58.86 - if (c == '\r' && ((o = getChar()) != '\n'))
58.87 - putChar(o);
58.88 -}
58.89 -
58.90 -void
58.91 -Scanner::eatSingleLine()
58.92 -{
58.93 - char c;
58.94 - while ((c = getChar()) != '\0') {
58.95 - if (c == '\n' || c == '\r') {
58.96 - calcNewLine(c);
58.97 - break;
58.98 - }
58.99 - }
58.100 -}
58.101 -
58.102 -bool
58.103 -Scanner::eatComment()
58.104 -{
58.105 - char c;
58.106 -
58.107 - while ((c = getChar()) != '\0') {
58.108 - while (c == '*') {
58.109 - c = getChar();
58.110 - if (c == '\0')
58.111 - return false;
58.112 - if (c == '/')
58.113 - return true;
58.114 - }
58.115 - if (c == '\r' || c == '\n')
58.116 - calcNewLine(c);
58.117 - }
58.118 -
58.119 - return false;
58.120 -}
58.121 -
58.122 -static inline bool
58.123 -IsDigit(char c)
58.124 -{
58.125 - return c >= '0' && c <= '9';
58.126 -}
58.127 -
58.128 -// Based off the logic in sc2.c's ftoi()...
58.129 -double
58.130 -Scanner::ParseDouble(const char *string)
58.131 -{
58.132 - const char *ptr = string;
58.133 -
58.134 - double number = 0.0;
58.135 - while (IsDigit(*ptr)) {
58.136 - number = (number * 10) + (*ptr - '0');
58.137 - ptr++;
58.138 - }
58.139 -
58.140 - assert(*ptr == '.');
58.141 - ptr++;
58.142 -
58.143 - double fraction = 0.0;
58.144 - double multiplier = 1.0;
58.145 - while (IsDigit(*ptr)) {
58.146 - fraction = (fraction * 10) + (*ptr - '0');
58.147 - multiplier = multiplier / 10.0;
58.148 - ptr++;
58.149 - }
58.150 -
58.151 - number += fraction * multiplier;
58.152 -
58.153 - if (*ptr++ == 'e') {
58.154 - int sign = 1;
58.155 - if (*ptr == '-') {
58.156 - sign = -1;
58.157 - ptr++;
58.158 - }
58.159 -
58.160 - int exponent = 0;
58.161 - while (IsDigit(*ptr)) {
58.162 - exponent = (exponent * 10) + (*ptr - '0');
58.163 - ptr++;
58.164 - }
58.165 -
58.166 - multiplier = pow(10.0, exponent * sign);
58.167 - number *= multiplier;
58.168 - }
58.169 -
58.170 - return number;
58.171 -}
58.172 -
58.173 -static inline bool
58.174 -IsHexDigit(char c)
58.175 -{
58.176 - return IsDigit(c) ||
58.177 - (c >= 'a' && c <= 'f') ||
58.178 - (c >= 'A' && c <= 'F');
58.179 -}
58.180 -
58.181 -// Based on the logic for litchar() in sc2.c.
58.182 -int
58.183 -Scanner::readEscapeCode()
58.184 -{
58.185 - char c = getChar();
58.186 - if (c == '\\')
58.187 - return c;
58.188 -
58.189 - switch (c) {
58.190 - case 'a':
58.191 - return '\a';
58.192 - case 'b':
58.193 - return '\b';
58.194 - case 'e':
58.195 - return 27; // Apparently \e is non-standard.
58.196 - case 'f':
58.197 - return '\f';
58.198 - case 'n':
58.199 - return '\n';
58.200 - case 'r':
58.201 - return '\r';
58.202 - case 't':
58.203 - return '\t';
58.204 - case 'v':
58.205 - return '\v';
58.206 -
58.207 - case 'x':
58.208 - {
58.209 - unsigned digits = 0;
58.210 - char r = 0;
58.211 -
58.212 - c = getChar();
58.213 - while (IsHexDigit(c) && digits < 2) {
58.214 - if (IsDigit(c))
58.215 - c = (c << 4) + (c - '0');
58.216 - else
58.217 - c = (c << 4) + (tolower(c) - 'a' + 10);
58.218 - digits++;
58.219 - c = getChar();
58.220 - }
58.221 -
58.222 - // Swallow a trailing ';'
58.223 - if (c != ';')
58.224 - putChar(c);
58.225 -
58.226 - return r;
58.227 - }
58.228 -
58.229 - case '\'':
58.230 - case '\"':
58.231 - case '%':
58.232 - return c;
58.233 -
58.234 - default:
58.235 - {
58.236 - if (IsDigit(c)) {
58.237 - // \ddd
58.238 - char r = 0;
58.239 - while (IsDigit(c)) {
58.240 - r = r * 10 + (c - '0');
58.241 - c = getChar();
58.242 - }
58.243 -
58.244 - // Swallow a trailing ;
58.245 - if (c != ';')
58.246 - putChar(c);
58.247 -
58.248 - return r;
58.249 - }
58.250 - cc_.reportError(begin(), Message_UnknownEscapeCode, c);
58.251 - return INT_MAX;
58.252 - }
58.253 - }
58.254 -}
58.255 -
58.256 -TokenKind
58.257 -Scanner::stringLiteral()
58.258 -{
58.259 - literal_.clear();
58.260 -
58.261 - for (;;) {
58.262 - char c = getChar();
58.263 - if (c == '\"')
58.264 - break;
58.265 - if (c == '\r' || c == '\n' || c == '\0') {
58.266 - cc_.reportError(begin(), Message_UnterminatedString);
58.267 - return TOK_ERROR;
58.268 - }
58.269 - if (c == '\\') {
58.270 - int code = readEscapeCode();
58.271 - if (code == INT_MAX)
58.272 - return TOK_ERROR;
58.273 - c = char(code);
58.274 - }
58.275 - if (!literal_.append(c))
58.276 - return TOK_ERROR;
58.277 - }
58.278 -
58.279 - if (!literal_.append('\0'))
58.280 - return TOK_ERROR;
58.281 -
58.282 - return TOK_STRING_LITERAL;
58.283 -}
58.284 -
58.285 -TokenKind
58.286 -Scanner::hexLiteral()
58.287 -{
58.288 - literal_.clear();
58.289 -
58.290 - char c;
58.291 - for (;;) {
58.292 - c = getChar();
58.293 - if (!IsHexDigit(c))
58.294 - break;
58.295 - if (!literal_.append(c))
58.296 - return TOK_ERROR;
58.297 - }
58.298 -
58.299 - putChar(c);
58.300 -
58.301 - if (!literal_.append('\0'))
58.302 - return TOK_ERROR;
58.303 - return TOK_HEX_LITERAL;
58.304 -}
58.305 -
58.306 -TokenKind
58.307 -Scanner::numberLiteral(char first)
58.308 -{
58.309 - literal_.clear();
58.310 - if (!literal_.append(first))
58.311 - return TOK_ERROR;
58.312 -
58.313 - char c;
58.314 - for (;;) {
58.315 - c = getChar();
58.316 - if (!IsDigit(c))
58.317 - break;
58.318 - if (!literal_.append(c))
58.319 - return TOK_ERROR;
58.320 - }
58.321 -
58.322 - // Detect a hexadecimal string.
58.323 - if (literal_.length() == 1 &&
58.324 - literal_[0] == '0' &&
58.325 - (c == 'x' || c == 'X'))
58.326 - {
58.327 - return hexLiteral();
58.328 - }
58.329 -
58.330 - if (c != '.') {
58.331 - putChar(c);
58.332 - if (!literal_.append('\0'))
58.333 - return TOK_ERROR;
58.334 - return TOK_INTEGER_LITERAL;
58.335 - }
58.336 - if (!literal_.append(c))
58.337 - return TOK_ERROR;
58.338 -
58.339 - c = getChar();
58.340 - if (!IsDigit(c)) {
58.341 - cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
58.342 - return TOK_ERROR;
58.343 - }
58.344 - if (!literal_.append(c))
58.345 - return TOK_ERROR;
58.346 -
58.347 - for (;;) {
58.348 - c = getChar();
58.349 - if (!IsDigit(c))
58.350 - break;
58.351 - if (!literal_.append(c))
58.352 - return TOK_ERROR;
58.353 - }
58.354 -
58.355 - if (c != 'e') {
58.356 - putChar(c);
58.357 - } else {
58.358 - if (!literal_.append(c))
58.359 - return TOK_ERROR;
58.360 - c = getChar();
58.361 - if (c == '-') {
58.362 - if (!literal_.append(c))
58.363 - return TOK_ERROR;
58.364 - c = getChar();
58.365 - }
58.366 - if (!IsDigit(c)) {
58.367 - cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
58.368 - return TOK_ERROR;
58.369 - }
58.370 - if (!literal_.append(c))
58.371 - return TOK_ERROR;
58.372 - for (;;) {
58.373 - c = getChar();
58.374 - if (!IsDigit(c)) {
58.375 - putChar(c);
58.376 - break;
58.377 - }
58.378 - if (!literal_.append(c))
58.379 - return TOK_ERROR;
58.380 - }
58.381 - }
58.382 -
58.383 - if (!literal_.append('\0'))
58.384 - return TOK_ERROR;
58.385 -
58.386 - return TOK_FLOAT_LITERAL;
58.387 -}
58.388 -
58.389 -static inline TokenKind
58.390 -FindIdentifier(const char *str)
58.391 -{
58.392 - if (!strcmp(str, "new"))
58.393 - return TOK_NEW;
58.394 - if (!strcmp(str, "for"))
58.395 - return TOK_FOR;
58.396 - if (!strcmp(str, "return"))
58.397 - return TOK_RETURN;
58.398 - if (!strcmp(str, "if"))
58.399 - return TOK_IF;
58.400 - if (!strcmp(str, "else"))
58.401 - return TOK_ELSE;
58.402 - if (!strcmp(str, "enum"))
58.403 - return TOK_ENUM;
58.404 - if (!strcmp(str, "while"))
58.405 - return TOK_WHILE;
58.406 - if (!strcmp(str, "do"))
58.407 - return TOK_DO;
58.408 - if (!strcmp(str, "break"))
58.409 - return TOK_BREAK;
58.410 - if (!strcmp(str, "continue"))
58.411 - return TOK_CONTINUE;
58.412 - if (!strcmp(str, "forward"))
58.413 - return TOK_FORWARD;
58.414 - if (!strcmp(str, "public"))
58.415 - return TOK_PUBLIC;
58.416 - if (!strcmp(str, "const"))
58.417 - return TOK_CONST;
58.418 - if (!strcmp(str, "native"))
58.419 - return TOK_NATIVE;
58.420 - if (!strcmp(str, "stock"))
58.421 - return TOK_STOCK;
58.422 - if (!strcmp(str, "true"))
58.423 - return TOK_TRUE;
58.424 - if (!strcmp(str, "false"))
58.425 - return TOK_FALSE;
58.426 - if (!strcmp(str, "struct"))
58.427 - return TOK_STRUCT;
58.428 - if (!strcmp(str, "switch"))
58.429 - return TOK_SWITCH;
58.430 - if (!strcmp(str, "case"))
58.431 - return TOK_CASE;
58.432 - if (!strcmp(str, "default"))
58.433 - return TOK_DEFAULT;
58.434 - if (!strcmp(str, "typedef"))
58.435 - return TOK_TYPEDEF;
58.436 - if (!strcmp(str, "void"))
58.437 - return TOK_VOID;
58.438 - if (!strcmp(str, "int"))
58.439 - return TOK_INT;
58.440 - if (!strcmp(str, "sizeof"))
58.441 - return TOK_SIZEOF;
58.442 - if (!strcmp(str, "import"))
58.443 - return TOK_IMPORT;
58.444 - if (!strcmp(str, "from"))
58.445 - return TOK_FROM;
58.446 - return TOK_NONE;
58.447 -}
58.448 -
58.449 -TokenKind
58.450 -Scanner::identifier(char first)
58.451 -{
58.452 - literal_.clear();
58.453 - if (!literal_.append(first))
58.454 - return TOK_ERROR;
58.455 -
58.456 - char c;
58.457 - for (;;) {
58.458 - c = getChar();
58.459 - if (!isascii(c) || (!isalnum(c) && c != '_'))
58.460 - break;
58.461 - if (!literal_.append(c))
58.462 - return TOK_ERROR;
58.463 - }
58.464 -
58.465 - if (!literal_.append('\0'))
58.466 - return TOK_ERROR;
58.467 -
58.468 - // Most keywords do not act as labels.
58.469 - TokenKind kind = FindIdentifier(literal());
58.470 - if (kind != TOK_NONE) {
58.471 - putChar(c);
58.472 - return kind;
58.473 - }
58.474 -
58.475 - if (c == ':' && allowTags_)
58.476 - return TOK_LABEL;
58.477 -
58.478 - putChar(c);
58.479 -
58.480 - // _ is a special case which acts as a tag and a keyword.
58.481 - if (!strcmp(literal(), "_"))
58.482 - return TOK_UNDERSCORE;
58.483 -
58.484 - return TOK_NAME;
58.485 -}
58.486 -
58.487 -TokenKind
58.488 -Scanner::next()
58.489 -{
58.490 - assert(!pushed_);
58.491 -
58.492 - for (;;) {
58.493 - begin_ = cur_;
58.494 -
58.495 - char c = getChar();
58.496 - switch (c) {
58.497 - case '/':
58.498 - {
58.499 - c = getChar();
58.500 - if (c == '/') {
58.501 - eatSingleLine();
58.502 - break;
58.503 - }
58.504 - if (c == '*') {
58.505 - if (!eatComment()) {
58.506 - cc_.reportError(begin(), Message_UnterminatedComment);
58.507 - return TOK_ERROR;
58.508 - }
58.509 - break;
58.510 - }
58.511 - putChar(c);
58.512 - return TOK_SLASH;
58.513 - }
58.514 -
58.515 - case '\n':
58.516 - case '\r':
58.517 - calcNewLine(c);
58.518 - break;
58.519 -
58.520 - case ';': return TOK_SEMICOLON;
58.521 - case '{': return TOK_LBRACE;
58.522 - case '}': return TOK_RBRACE;
58.523 - case '(': return TOK_LPAREN;
58.524 - case ')': return TOK_RPAREN;
58.525 - case '[': return TOK_LBRACKET;
58.526 - case ']': return TOK_RBRACKET;
58.527 - case '~': return TOK_TILDE;
58.528 - case '?': return TOK_QMARK;
58.529 - case ':': return TOK_COLON;
58.530 -
58.531 - case '.':
58.532 - c = getChar();
58.533 - if (c == '.') {
58.534 - c = getChar();
58.535 - if (c == '.')
58.536 - return TOK_ELLIPSES;
58.537 - cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
58.538 - return TOK_ERROR;
58.539 - }
58.540 - putChar(c);
58.541 - return TOK_DOT;
58.542 -
58.543 - case '*':
58.544 - c = getChar();
58.545 - if (c == '=')
58.546 - return TOK_ASSIGN_MUL;
58.547 - putChar(c);
58.548 - return TOK_STAR;
58.549 -
58.550 - case '+':
58.551 - c = getChar();
58.552 - if (c == '=')
58.553 - return TOK_ASSIGN_ADD;
58.554 - if (c == '+')
58.555 - return TOK_INCREMENT;
58.556 - putChar(c);
58.557 - return TOK_PLUS;
58.558 -
58.559 - case '&':
58.560 - c = getChar();
58.561 - if (c == '=')
58.562 - return TOK_ASSIGN_BITAND;
58.563 - if (c == '&')
58.564 - return TOK_AND;
58.565 - putChar(c);
58.566 - return TOK_BITAND;
58.567 -
58.568 - case '|':
58.569 - c = getChar();
58.570 - if (c == '=')
58.571 - return TOK_ASSIGN_BITOR;
58.572 - if (c == '|')
58.573 - return TOK_OR;
58.574 - putChar(c);
58.575 - return TOK_BITOR;
58.576 -
58.577 - case '^':
58.578 - c = getChar();
58.579 - if (c == '=')
58.580 - return TOK_ASSIGN_BITXOR;
58.581 - putChar(c);
58.582 - return TOK_BITXOR;
58.583 -
58.584 - case '%':
58.585 - c = getChar();
58.586 - if (c == '=')
58.587 - return TOK_ASSIGN_MOD;
58.588 - putChar(c);
58.589 - return TOK_PERCENT;
58.590 -
58.591 - case '-':
58.592 - c = getChar();
58.593 - if (c == '=')
58.594 - return TOK_ASSIGN_SUB;
58.595 - if (c == '-')
58.596 - return TOK_DECREMENT;
58.597 - putChar(c);
58.598 - return TOK_MINUS;
58.599 -
58.600 - case ',': return TOK_COMMA;
58.601 - case '\0': return TOK_EOF;
58.602 -
58.603 - case '!':
58.604 - c = getChar();
58.605 - if (c == '=')
58.606 - return TOK_NOTEQUALS;
58.607 - putChar(c);
58.608 - return TOK_NOT;
58.609 -
58.610 - case '=':
58.611 - c = getChar();
58.612 - if (c == '=')
58.613 - return TOK_EQUALS;
58.614 - putChar(c);
58.615 - return TOK_ASSIGN;
58.616 -
58.617 -
58.618 - case '<':
58.619 - c = getChar();
58.620 - if (c == '=')
58.621 - return TOK_LE;
58.622 - if (c == '<') {
58.623 - c = getChar();
58.624 - if (c == '=')
58.625 - return TOK_ASSIGN_SHL;
58.626 - putChar(c);
58.627 - return TOK_SHL;
58.628 - }
58.629 - putChar(c);
58.630 - return TOK_LT;
58.631 -
58.632 - case '>':
58.633 - c = getChar();
58.634 - if (c == '=')
58.635 - return TOK_GE;
58.636 - if (c == '>') {
58.637 - c = getChar();
58.638 - if (c == '>') {
58.639 - c = getChar();
58.640 - if (c == '=')
58.641 - return TOK_ASSIGN_USHR;
58.642 - putChar(c);
58.643 - return TOK_USHR;
58.644 - }
58.645 - return TOK_SHR;
58.646 - }
58.647 - putChar(c);
58.648 - return TOK_GT;
58.649 -
58.650 - case ' ':
58.651 - case '\t':
58.652 - case '\f':
58.653 - break;
58.654 -
58.655 - case '"':
58.656 - return stringLiteral();
58.657 -
58.658 - default:
58.659 - if (c >= '0' && c <= '9')
58.660 - return numberLiteral(c);
58.661 - if (c == '_' || (isascii(c) && isalpha(c)))
58.662 - return identifier(c);
58.663 - cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
58.664 - return TOK_ERROR;
58.665 - }
58.666 - }
58.667 -}
58.668 -
58.669 -TokenKind
58.670 -Scanner::scan()
58.671 -{
58.672 - if (pushed_) {
58.673 - pushed_ = false;
58.674 - return lastToken_;
58.675 - }
58.676 - lastToken_ = next();
58.677 - return lastToken_;
58.678 -}
58.679 -
58.680 -TokenKind
58.681 -Scanner::peek()
58.682 -{
58.683 - if (pushed_)
58.684 - return lastToken_;
58.685 - scan();
58.686 - pushed_ = true;
58.687 - return lastToken_;
58.688 -}
58.689 +/* vim: set ts=4 sw=4 tw=99 et:
58.690 + *
58.691 + * Copyright (C) 2012 David Anderson
58.692 + *
58.693 + * This file is part of JITCraft.
58.694 + *
58.695 + * JITCraft is free software: you can redistribute it and/or modify it under
58.696 + * the terms of the GNU General Public License as published by the Free
58.697 + * Software Foundation, either version 3 of the License, or (at your option)
58.698 + * any later version.
58.699 + *
58.700 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
58.701 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
58.702 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
58.703 + *
58.704 + * You should have received a copy of the GNU General Public License along with
58.705 + * JITCraft. If not, see http://www.gnu.org/licenses/.
58.706 + */
58.707 +#include <assert.h>
58.708 +#include <ctype.h>
58.709 +#include <math.h>
58.710 +#include <limits.h>
58.711 +#include <string.h>
58.712 +#include "../Utility.h"
58.713 +#include "../Heap-inl.h"
58.714 +#include "../Handles-inl.h"
58.715 +#include "Scanner.h"
58.716 +
58.717 +using namespace ke;
58.718 +
58.719 +const char *ke::TokenNames[] =
58.720 +{
58.721 +#define _(name, str) str,
58.722 + TOKENMAP(_)
58.723 +#undef _
58.724 + NULL
58.725 +};
58.726 +
58.727 +Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
58.728 + : cc_(cc),
58.729 + stream_(stream),
58.730 + length_(length),
58.731 + pushed_(false),
58.732 + allowTags_(true),
58.733 + saved_('\0'),
58.734 + pos_(stream_)
58.735 +{
58.736 + cur_.line = 1;
58.737 + cur_.col = 1;
58.738 + last_ = cur_;
58.739 +}
58.740 +
58.741 +char
58.742 +Scanner::getChar()
58.743 +{
58.744 + if (saved_ != '\0') {
58.745 + char temp = saved_;
58.746 + saved_ = '\0';
58.747 + return temp;
58.748 + }
58.749 + if (pos_ >= stream_ + length_)
58.750 + return '\0';
58.751 + last_.col = cur_.col++;
58.752 + return *pos_++;
58.753 +}
58.754 +
58.755 +void
58.756 +Scanner::putChar(char c)
58.757 +{
58.758 + assert(saved_ == '\0');
58.759 + saved_ = c;
58.760 + cur_.col = last_.col;
58.761 +}
58.762 +
58.763 +void
58.764 +Scanner::calcNewLine(char c)
58.765 +{
58.766 + cur_.line++;
58.767 + cur_.col = 1;
58.768 + last_ = cur_;
58.769 +
58.770 + char o;
58.771 + if (c == '\r' && ((o = getChar()) != '\n'))
58.772 + putChar(o);
58.773 +}
58.774 +
58.775 +void
58.776 +Scanner::eatSingleLine()
58.777 +{
58.778 + char c;
58.779 + while ((c = getChar()) != '\0') {
58.780 + if (c == '\n' || c == '\r') {
58.781 + calcNewLine(c);
58.782 + break;
58.783 + }
58.784 + }
58.785 +}
58.786 +
58.787 +bool
58.788 +Scanner::eatComment()
58.789 +{
58.790 + char c;
58.791 +
58.792 + while ((c = getChar()) != '\0') {
58.793 + while (c == '*') {
58.794 + c = getChar();
58.795 + if (c == '\0')
58.796 + return false;
58.797 + if (c == '/')
58.798 + return true;
58.799 + }
58.800 + if (c == '\r' || c == '\n')
58.801 + calcNewLine(c);
58.802 + }
58.803 +
58.804 + return false;
58.805 +}
58.806 +
58.807 +static inline bool
58.808 +IsDigit(char c)
58.809 +{
58.810 + return c >= '0' && c <= '9';
58.811 +}
58.812 +
58.813 +// Based off the logic in sc2.c's ftoi()...
58.814 +double
58.815 +Scanner::ParseDouble(const char *string)
58.816 +{
58.817 + const char *ptr = string;
58.818 +
58.819 + double number = 0.0;
58.820 + while (IsDigit(*ptr)) {
58.821 + number = (number * 10) + (*ptr - '0');
58.822 + ptr++;
58.823 + }
58.824 +
58.825 + assert(*ptr == '.');
58.826 + ptr++;
58.827 +
58.828 + double fraction = 0.0;
58.829 + double multiplier = 1.0;
58.830 + while (IsDigit(*ptr)) {
58.831 + fraction = (fraction * 10) + (*ptr - '0');
58.832 + multiplier = multiplier / 10.0;
58.833 + ptr++;
58.834 + }
58.835 +
58.836 + number += fraction * multiplier;
58.837 +
58.838 + if (*ptr++ == 'e') {
58.839 + int sign = 1;
58.840 + if (*ptr == '-') {
58.841 + sign = -1;
58.842 + ptr++;
58.843 + }
58.844 +
58.845 + int exponent = 0;
58.846 + while (IsDigit(*ptr)) {
58.847 + exponent = (exponent * 10) + (*ptr - '0');
58.848 + ptr++;
58.849 + }
58.850 +
58.851 + multiplier = pow(10.0, exponent * sign);
58.852 + number *= multiplier;
58.853 + }
58.854 +
58.855 + return number;
58.856 +}
58.857 +
58.858 +static inline bool
58.859 +IsHexDigit(char c)
58.860 +{
58.861 + return IsDigit(c) ||
58.862 + (c >= 'a' && c <= 'f') ||
58.863 + (c >= 'A' && c <= 'F');
58.864 +}
58.865 +
58.866 +// Based on the logic for litchar() in sc2.c.
58.867 +int
58.868 +Scanner::readEscapeCode()
58.869 +{
58.870 + char c = getChar();
58.871 + if (c == '\\')
58.872 + return c;
58.873 +
58.874 + switch (c) {
58.875 + case 'a':
58.876 + return '\a';
58.877 + case 'b':
58.878 + return '\b';
58.879 + case 'e':
58.880 + return 27; // Apparently \e is non-standard.
58.881 + case 'f':
58.882 + return '\f';
58.883 + case 'n':
58.884 + return '\n';
58.885 + case 'r':
58.886 + return '\r';
58.887 + case 't':
58.888 + return '\t';
58.889 + case 'v':
58.890 + return '\v';
58.891 +
58.892 + case 'x':
58.893 + {
58.894 + unsigned digits = 0;
58.895 + char r = 0;
58.896 +
58.897 + c = getChar();
58.898 + while (IsHexDigit(c) && digits < 2) {
58.899 + if (IsDigit(c))
58.900 + c = (c << 4) + (c - '0');
58.901 + else
58.902 + c = (c << 4) + (tolower(c) - 'a' + 10);
58.903 + digits++;
58.904 + c = getChar();
58.905 + }
58.906 +
58.907 + // Swallow a trailing ';'
58.908 + if (c != ';')
58.909 + putChar(c);
58.910 +
58.911 + return r;
58.912 + }
58.913 +
58.914 + case '\'':
58.915 + case '\"':
58.916 + case '%':
58.917 + return c;
58.918 +
58.919 + default:
58.920 + {
58.921 + if (IsDigit(c)) {
58.922 + // \ddd
58.923 + char r = 0;
58.924 + while (IsDigit(c)) {
58.925 + r = r * 10 + (c - '0');
58.926 + c = getChar();
58.927 + }
58.928 +
58.929 + // Swallow a trailing ;
58.930 + if (c != ';')
58.931 + putChar(c);
58.932 +
58.933 + return r;
58.934 + }
58.935 + cc_.reportError(begin(), Message_UnknownEscapeCode, c);
58.936 + return INT_MAX;
58.937 + }
58.938 + }
58.939 +}
58.940 +
58.941 +TokenKind
58.942 +Scanner::stringLiteral()
58.943 +{
58.944 + literal_.clear();
58.945 +
58.946 + for (;;) {
58.947 + char c = getChar();
58.948 + if (c == '\"')
58.949 + break;
58.950 + if (c == '\r' || c == '\n' || c == '\0') {
58.951 + cc_.reportError(begin(), Message_UnterminatedString);
58.952 + return TOK_ERROR;
58.953 + }
58.954 + if (c == '\\') {
58.955 + int code = readEscapeCode();
58.956 + if (code == INT_MAX)
58.957 + return TOK_ERROR;
58.958 + c = char(code);
58.959 + }
58.960 + if (!literal_.append(c))
58.961 + return TOK_ERROR;
58.962 + }
58.963 +
58.964 + if (!literal_.append('\0'))
58.965 + return TOK_ERROR;
58.966 +
58.967 + return TOK_STRING_LITERAL;
58.968 +}
58.969 +
58.970 +TokenKind
58.971 +Scanner::hexLiteral()
58.972 +{
58.973 + literal_.clear();
58.974 +
58.975 + char c;
58.976 + for (;;) {
58.977 + c = getChar();
58.978 + if (!IsHexDigit(c))
58.979 + break;
58.980 + if (!literal_.append(c))
58.981 + return TOK_ERROR;
58.982 + }
58.983 +
58.984 + putChar(c);
58.985 +
58.986 + if (!literal_.append('\0'))
58.987 + return TOK_ERROR;
58.988 + return TOK_HEX_LITERAL;
58.989 +}
58.990 +
58.991 +TokenKind
58.992 +Scanner::numberLiteral(char first)
58.993 +{
58.994 + literal_.clear();
58.995 + if (!literal_.append(first))
58.996 + return TOK_ERROR;
58.997 +
58.998 + char c;
58.999 + for (;;) {
58.1000 + c = getChar();
58.1001 + if (!IsDigit(c))
58.1002 + break;
58.1003 + if (!literal_.append(c))
58.1004 + return TOK_ERROR;
58.1005 + }
58.1006 +
58.1007 + // Detect a hexadecimal string.
58.1008 + if (literal_.length() == 1 &&
58.1009 + literal_[0] == '0' &&
58.1010 + (c == 'x' || c == 'X'))
58.1011 + {
58.1012 + return hexLiteral();
58.1013 + }
58.1014 +
58.1015 + if (c != '.') {
58.1016 + putChar(c);
58.1017 + if (!literal_.append('\0'))
58.1018 + return TOK_ERROR;
58.1019 + return TOK_INTEGER_LITERAL;
58.1020 + }
58.1021 + if (!literal_.append(c))
58.1022 + return TOK_ERROR;
58.1023 +
58.1024 + c = getChar();
58.1025 + if (!IsDigit(c)) {
58.1026 + cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
58.1027 + return TOK_ERROR;
58.1028 + }
58.1029 + if (!literal_.append(c))
58.1030 + return TOK_ERROR;
58.1031 +
58.1032 + for (;;) {
58.1033 + c = getChar();
58.1034 + if (!IsDigit(c))
58.1035 + break;
58.1036 + if (!literal_.append(c))
58.1037 + return TOK_ERROR;
58.1038 + }
58.1039 +
58.1040 + if (c != 'e') {
58.1041 + putChar(c);
58.1042 + } else {
58.1043 + if (!literal_.append(c))
58.1044 + return TOK_ERROR;
58.1045 + c = getChar();
58.1046 + if (c == '-') {
58.1047 + if (!literal_.append(c))
58.1048 + return TOK_ERROR;
58.1049 + c = getChar();
58.1050 + }
58.1051 + if (!IsDigit(c)) {
58.1052 + cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
58.1053 + return TOK_ERROR;
58.1054 + }
58.1055 + if (!literal_.append(c))
58.1056 + return TOK_ERROR;
58.1057 + for (;;) {
58.1058 + c = getChar();
58.1059 + if (!IsDigit(c)) {
58.1060 + putChar(c);
58.1061 + break;
58.1062 + }
58.1063 + if (!literal_.append(c))
58.1064 + return TOK_ERROR;
58.1065 + }
58.1066 + }
58.1067 +
58.1068 + if (!literal_.append('\0'))
58.1069 + return TOK_ERROR;
58.1070 +
58.1071 + return TOK_FLOAT_LITERAL;
58.1072 +}
58.1073 +
58.1074 +static inline TokenKind
58.1075 +FindIdentifier(const char *str)
58.1076 +{
58.1077 + if (!strcmp(str, "new"))
58.1078 + return TOK_NEW;
58.1079 + if (!strcmp(str, "for"))
58.1080 + return TOK_FOR;
58.1081 + if (!strcmp(str, "return"))
58.1082 + return TOK_RETURN;
58.1083 + if (!strcmp(str, "if"))
58.1084 + return TOK_IF;
58.1085 + if (!strcmp(str, "else"))
58.1086 + return TOK_ELSE;
58.1087 + if (!strcmp(str, "enum"))
58.1088 + return TOK_ENUM;
58.1089 + if (!strcmp(str, "while"))
58.1090 + return TOK_WHILE;
58.1091 + if (!strcmp(str, "do"))
58.1092 + return TOK_DO;
58.1093 + if (!strcmp(str, "break"))
58.1094 + return TOK_BREAK;
58.1095 + if (!strcmp(str, "continue"))
58.1096 + return TOK_CONTINUE;
58.1097 + if (!strcmp(str, "forward"))
58.1098 + return TOK_FORWARD;
58.1099 + if (!strcmp(str, "public"))
58.1100 + return TOK_PUBLIC;
58.1101 + if (!strcmp(str, "const"))
58.1102 + return TOK_CONST;
58.1103 + if (!strcmp(str, "native"))
58.1104 + return TOK_NATIVE;
58.1105 + if (!strcmp(str, "stock"))
58.1106 + return TOK_STOCK;
58.1107 + if (!strcmp(str, "true"))
58.1108 + return TOK_TRUE;
58.1109 + if (!strcmp(str, "false"))
58.1110 + return TOK_FALSE;
58.1111 + if (!strcmp(str, "struct"))
58.1112 + return TOK_STRUCT;
58.1113 + if (!strcmp(str, "switch"))
58.1114 + return TOK_SWITCH;
58.1115 + if (!strcmp(str, "case"))
58.1116 + return TOK_CASE;
58.1117 + if (!strcmp(str, "default"))
58.1118 + return TOK_DEFAULT;
58.1119 + if (!strcmp(str, "typedef"))
58.1120 + return TOK_TYPEDEF;
58.1121 + if (!strcmp(str, "void"))
58.1122 + return TOK_VOID;
58.1123 + if (!strcmp(str, "int"))
58.1124 + return TOK_INT;
58.1125 + if (!strcmp(str, "sizeof"))
58.1126 + return TOK_SIZEOF;
58.1127 + if (!strcmp(str, "import"))
58.1128 + return TOK_IMPORT;
58.1129 + if (!strcmp(str, "from"))
58.1130 + return TOK_FROM;
58.1131 + return TOK_NONE;
58.1132 +}
58.1133 +
58.1134 +TokenKind
58.1135 +Scanner::identifier(char first)
58.1136 +{
58.1137 + literal_.clear();
58.1138 + if (!literal_.append(first))
58.1139 + return TOK_ERROR;
58.1140 +
58.1141 + char c;
58.1142 + for (;;) {
58.1143 + c = getChar();
58.1144 + if (!isascii(c) || (!isalnum(c) && c != '_'))
58.1145 + break;
58.1146 + if (!literal_.append(c))
58.1147 + return TOK_ERROR;
58.1148 + }
58.1149 +
58.1150 + if (!literal_.append('\0'))
58.1151 + return TOK_ERROR;
58.1152 +
58.1153 + // Most keywords do not act as labels.
58.1154 + TokenKind kind = FindIdentifier(literal());
58.1155 + if (kind != TOK_NONE) {
58.1156 + putChar(c);
58.1157 + return kind;
58.1158 + }
58.1159 +
58.1160 + if (c == ':' && allowTags_)
58.1161 + return TOK_LABEL;
58.1162 +
58.1163 + putChar(c);
58.1164 +
58.1165 + // _ is a special case which acts as a tag and a keyword.
58.1166 + if (!strcmp(literal(), "_"))
58.1167 + return TOK_UNDERSCORE;
58.1168 +
58.1169 + return TOK_NAME;
58.1170 +}
58.1171 +
58.1172 +TokenKind
58.1173 +Scanner::next()
58.1174 +{
58.1175 + assert(!pushed_);
58.1176 +
58.1177 + for (;;) {
58.1178 + begin_ = cur_;
58.1179 +
58.1180 + char c = getChar();
58.1181 + switch (c) {
58.1182 + case '/':
58.1183 + {
58.1184 + c = getChar();
58.1185 + if (c == '/') {
58.1186 + eatSingleLine();
58.1187 + break;
58.1188 + }
58.1189 + if (c == '*') {
58.1190 + if (!eatComment()) {
58.1191 + cc_.reportError(begin(), Message_UnterminatedComment);
58.1192 + return TOK_ERROR;
58.1193 + }
58.1194 + break;
58.1195 + }
58.1196 + putChar(c);
58.1197 + return TOK_SLASH;
58.1198 + }
58.1199 +
58.1200 + case '\n':
58.1201 + case '\r':
58.1202 + calcNewLine(c);
58.1203 + break;
58.1204 +
58.1205 + case ';': return TOK_SEMICOLON;
58.1206 + case '{': return TOK_LBRACE;
58.1207 + case '}': return TOK_RBRACE;
58.1208 + case '(': return TOK_LPAREN;
58.1209 + case ')': return TOK_RPAREN;
58.1210 + case '[': return TOK_LBRACKET;
58.1211 + case ']': return TOK_RBRACKET;
58.1212 + case '~': return TOK_TILDE;
58.1213 + case '?': return TOK_QMARK;
58.1214 + case ':': return TOK_COLON;
58.1215 +
58.1216 + case '.':
58.1217 + c = getChar();
58.1218 + if (c == '.') {
58.1219 + c = getChar();
58.1220 + if (c == '.')
58.1221 + return TOK_ELLIPSES;
58.1222 + cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
58.1223 + return TOK_ERROR;
58.1224 + }
58.1225 + putChar(c);
58.1226 + return TOK_DOT;
58.1227 +
58.1228 + case '*':
58.1229 + c = getChar();
58.1230 + if (c == '=')
58.1231 + return TOK_ASSIGN_MUL;
58.1232 + putChar(c);
58.1233 + return TOK_STAR;
58.1234 +
58.1235 + case '+':
58.1236 + c = getChar();
58.1237 + if (c == '=')
58.1238 + return TOK_ASSIGN_ADD;
58.1239 + if (c == '+')
58.1240 + return TOK_INCREMENT;
58.1241 + putChar(c);
58.1242 + return TOK_PLUS;
58.1243 +
58.1244 + case '&':
58.1245 + c = getChar();
58.1246 + if (c == '=')
58.1247 + return TOK_ASSIGN_BITAND;
58.1248 + if (c == '&')
58.1249 + return TOK_AND;
58.1250 + putChar(c);
58.1251 + return TOK_BITAND;
58.1252 +
58.1253 + case '|':
58.1254 + c = getChar();
58.1255 + if (c == '=')
58.1256 + return TOK_ASSIGN_BITOR;
58.1257 + if (c == '|')
58.1258 + return TOK_OR;
58.1259 + putChar(c);
58.1260 + return TOK_BITOR;
58.1261 +
58.1262 + case '^':
58.1263 + c = getChar();
58.1264 + if (c == '=')
58.1265 + return TOK_ASSIGN_BITXOR;
58.1266 + putChar(c);
58.1267 + return TOK_BITXOR;
58.1268 +
58.1269 + case '%':
58.1270 + c = getChar();
58.1271 + if (c == '=')
58.1272 + return TOK_ASSIGN_MOD;
58.1273 + putChar(c);
58.1274 + return TOK_PERCENT;
58.1275 +
58.1276 + case '-':
58.1277 + c = getChar();
58.1278 + if (c == '=')
58.1279 + return TOK_ASSIGN_SUB;
58.1280 + if (c == '-')
58.1281 + return TOK_DECREMENT;
58.1282 + putChar(c);
58.1283 + return TOK_MINUS;
58.1284 +
58.1285 + case ',': return TOK_COMMA;
58.1286 + case '\0': return TOK_EOF;
58.1287 +
58.1288 + case '!':
58.1289 + c = getChar();
58.1290 + if (c == '=')
58.1291 + return TOK_NOTEQUALS;
58.1292 + putChar(c);
58.1293 + return TOK_NOT;
58.1294 +
58.1295 + case '=':
58.1296 + c = getChar();
58.1297 + if (c == '=')
58.1298 + return TOK_EQUALS;
58.1299 + putChar(c);
58.1300 + return TOK_ASSIGN;
58.1301 +
58.1302 +
58.1303 + case '<':
58.1304 + c = getChar();
58.1305 + if (c == '=')
58.1306 + return TOK_LE;
58.1307 + if (c == '<') {
58.1308 + c = getChar();
58.1309 + if (c == '=')
58.1310 + return TOK_ASSIGN_SHL;
58.1311 + putChar(c);
58.1312 + return TOK_SHL;
58.1313 + }
58.1314 + putChar(c);
58.1315 + return TOK_LT;
58.1316 +
58.1317 + case '>':
58.1318 + c = getChar();
58.1319 + if (c == '=')
58.1320 + return TOK_GE;
58.1321 + if (c == '>') {
58.1322 + c = getChar();
58.1323 + if (c == '>') {
58.1324 + c = getChar();
58.1325 + if (c == '=')
58.1326 + return TOK_ASSIGN_USHR;
58.1327 + putChar(c);
58.1328 + return TOK_USHR;
58.1329 + }
58.1330 + return TOK_SHR;
58.1331 + }
58.1332 + putChar(c);
58.1333 + return TOK_GT;
58.1334 +
58.1335 + case ' ':
58.1336 + case '\t':
58.1337 + case '\f':
58.1338 + break;
58.1339 +
58.1340 + case '"':
58.1341 + return stringLiteral();
58.1342 +
58.1343 + default:
58.1344 + if (c >= '0' && c <= '9')
58.1345 + return numberLiteral(c);
58.1346 + if (c == '_' || (isascii(c) && isalpha(c)))
58.1347 + return identifier(c);
58.1348 + cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
58.1349 + return TOK_ERROR;
58.1350 + }
58.1351 + }
58.1352 +}
58.1353 +
58.1354 +TokenKind
58.1355 +Scanner::scan()
58.1356 +{
58.1357 + if (pushed_) {
58.1358 + pushed_ = false;
58.1359 + return lastToken_;
58.1360 + }
58.1361 + lastToken_ = next();
58.1362 + return lastToken_;
58.1363 +}
58.1364 +
58.1365 +TokenKind
58.1366 +Scanner::peek()
58.1367 +{
58.1368 + if (pushed_)
58.1369 + return lastToken_;
58.1370 + scan();
58.1371 + pushed_ = true;
58.1372 + return lastToken_;
58.1373 +}
59.1 --- a/src/compiler/Scanner.h Mon Jun 10 00:46:29 2013 +0100
59.2 +++ b/src/compiler/Scanner.h Mon Jun 10 01:04:43 2013 +0100
59.3 @@ -1,114 +1,114 @@
59.4 -/* vim: set ts=4 sw=4 tw=99 et:
59.5 - *
59.6 - * Copyright (C) 2012 David Anderson
59.7 - *
59.8 - * This file is part of SourcePawn.
59.9 - *
59.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
59.11 - * the terms of the GNU General Public License as published by the Free
59.12 - * Software Foundation, either version 3 of the License, or (at your option)
59.13 - * any later version.
59.14 - *
59.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
59.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
59.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
59.18 - *
59.19 - * You should have received a copy of the GNU General Public License along with
59.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
59.21 - */
59.22 -#ifndef _include_jitcraft_scanner_h_
59.23 -#define _include_jitcraft_scanner_h_
59.24 -
59.25 -#include "Token.h"
59.26 -#include "CompileContext.h"
59.27 -#include "../Opcodes.h"
59.28 -#include "../Vector.h"
59.29 -
59.30 -namespace ke {
59.31 -
59.32 -class Scanner
59.33 -{
59.34 - template <bool Enabled>
59.35 - friend class AutoAllowTags;
59.36 -
59.37 - CompileContext &cc_;
59.38 - const char *stream_;
59.39 - size_t length_;
59.40 - bool pushed_;
59.41 - bool allowTags_;
59.42 - char saved_;
59.43 - const char *pos_;
59.44 - Vector<char> literal_;
59.45 - TokenKind lastToken_;
59.46 - SourcePosition last_;
59.47 - SourcePosition cur_;
59.48 - SourcePosition begin_;
59.49 -
59.50 - private:
59.51 - char getChar();
59.52 - void putChar(char c);
59.53 - void eatSingleLine();
59.54 - bool eatComment();
59.55 - void calcNewLine(char c);
59.56 - int readEscapeCode();
59.57 - TokenKind stringLiteral();
59.58 - TokenKind hexLiteral();
59.59 - TokenKind numberLiteral(char first);
59.60 - TokenKind identifier(char first);
59.61 -
59.62 - TokenKind next();
59.63 -
59.64 - public:
59.65 - Scanner(CompileContext &cc, const char *stream, size_t length);
59.66 -
59.67 - static double ParseDouble(const char *string);
59.68 -
59.69 - TokenKind scan();
59.70 - TokenKind peek();
59.71 - TokenKind last() const {
59.72 - return lastToken_;
59.73 - }
59.74 -
59.75 - bool tagsEnabled() const {
59.76 - return allowTags_;
59.77 - }
59.78 - void setTagsEnabled(bool enabled) {
59.79 - allowTags_ = enabled;
59.80 - }
59.81 -
59.82 - // Beginning source position of the last instruction.
59.83 - SourcePosition begin() const {
59.84 - return begin_;
59.85 - }
59.86 -
59.87 - // Note: the literal may have embedded NUL characters.
59.88 - const char *literal() const {
59.89 - return literal_.buffer();
59.90 - }
59.91 - size_t literal_length() const {
59.92 - return literal_.length() - 1;
59.93 - }
59.94 -};
59.95 -
59.96 -template <bool Enabled>
59.97 -class AutoAllowTags
59.98 -{
59.99 - Scanner &scanner_;
59.100 - bool prev_;
59.101 -
59.102 - public:
59.103 - AutoAllowTags(Scanner &scanner)
59.104 - : scanner_(scanner),
59.105 - prev_(scanner_.tagsEnabled())
59.106 - {
59.107 - scanner_.setTagsEnabled(Enabled);
59.108 - }
59.109 - ~AutoAllowTags()
59.110 - {
59.111 - scanner_.setTagsEnabled(prev_);
59.112 - }
59.113 -};
59.114 -
59.115 -} // namespace ke
59.116 -
59.117 -#endif // _include_jitcraft_scanner_h_
59.118 +/* vim: set ts=4 sw=4 tw=99 et:
59.119 + *
59.120 + * Copyright (C) 2012 David Anderson
59.121 + *
59.122 + * This file is part of SourcePawn.
59.123 + *
59.124 + * SourcePawn is free software: you can redistribute it and/or modify it under
59.125 + * the terms of the GNU General Public License as published by the Free
59.126 + * Software Foundation, either version 3 of the License, or (at your option)
59.127 + * any later version.
59.128 + *
59.129 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
59.130 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
59.131 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
59.132 + *
59.133 + * You should have received a copy of the GNU General Public License along with
59.134 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
59.135 + */
59.136 +#ifndef _include_jitcraft_scanner_h_
59.137 +#define _include_jitcraft_scanner_h_
59.138 +
59.139 +#include "Token.h"
59.140 +#include "CompileContext.h"
59.141 +#include "../Opcodes.h"
59.142 +#include "../Vector.h"
59.143 +
59.144 +namespace ke {
59.145 +
59.146 +class Scanner
59.147 +{
59.148 + template <bool Enabled>
59.149 + friend class AutoAllowTags;
59.150 +
59.151 + CompileContext &cc_;
59.152 + const char *stream_;
59.153 + size_t length_;
59.154 + bool pushed_;
59.155 + bool allowTags_;
59.156 + char saved_;
59.157 + const char *pos_;
59.158 + Vector<char> literal_;
59.159 + TokenKind lastToken_;
59.160 + SourcePosition last_;
59.161 + SourcePosition cur_;
59.162 + SourcePosition begin_;
59.163 +
59.164 + private:
59.165 + char getChar();
59.166 + void putChar(char c);
59.167 + void eatSingleLine();
59.168 + bool eatComment();
59.169 + void calcNewLine(char c);
59.170 + int readEscapeCode();
59.171 + TokenKind stringLiteral();
59.172 + TokenKind hexLiteral();
59.173 + TokenKind numberLiteral(char first);
59.174 + TokenKind identifier(char first);
59.175 +
59.176 + TokenKind next();
59.177 +
59.178 + public:
59.179 + Scanner(CompileContext &cc, const char *stream, size_t length);
59.180 +
59.181 + static double ParseDouble(const char *string);
59.182 +
59.183 + TokenKind scan();
59.184 + TokenKind peek();
59.185 + TokenKind last() const {
59.186 + return lastToken_;
59.187 + }
59.188 +
59.189 + bool tagsEnabled() const {
59.190 + return allowTags_;
59.191 + }
59.192 + void setTagsEnabled(bool enabled) {
59.193 + allowTags_ = enabled;
59.194 + }
59.195 +
59.196 + // Beginning source position of the last instruction.
59.197 + SourcePosition begin() const {
59.198 + return begin_;
59.199 + }
59.200 +
59.201 + // Note: the literal may have embedded NUL characters.
59.202 + const char *literal() const {
59.203 + return literal_.buffer();
59.204 + }
59.205 + size_t literal_length() const {
59.206 + return literal_.length() - 1;
59.207 + }
59.208 +};
59.209 +
59.210 +template <bool Enabled>
59.211 +class AutoAllowTags
59.212 +{
59.213 + Scanner &scanner_;
59.214 + bool prev_;
59.215 +
59.216 + public:
59.217 + AutoAllowTags(Scanner &scanner)
59.218 + : scanner_(scanner),
59.219 + prev_(scanner_.tagsEnabled())
59.220 + {
59.221 + scanner_.setTagsEnabled(Enabled);
59.222 + }
59.223 + ~AutoAllowTags()
59.224 + {
59.225 + scanner_.setTagsEnabled(prev_);
59.226 + }
59.227 +};
59.228 +
59.229 +} // namespace ke
59.230 +
59.231 +#endif // _include_jitcraft_scanner_h_
60.1 --- a/src/compiler/Scopes.cpp Mon Jun 10 00:46:29 2013 +0100
60.2 +++ b/src/compiler/Scopes.cpp Mon Jun 10 01:04:43 2013 +0100
60.3 @@ -1,194 +1,194 @@
60.4 -/* vim: set ts=4 sw=4 tw=99 et:
60.5 - *
60.6 - * Copyright (C) 2012 David Anderson
60.7 - *
60.8 - * This file is part of JITCraft.
60.9 - *
60.10 - * JITCraft is free software: you can redistribute it and/or modify it under
60.11 - * the terms of the GNU General Public License as published by the Free
60.12 - * Software Foundation, either version 3 of the License, or (at your option)
60.13 - * any later version.
60.14 - *
60.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
60.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
60.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
60.18 - *
60.19 - * You should have received a copy of the GNU General Public License along with
60.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
60.21 - */
60.22 -#include "../Zone.h"
60.23 -#include "../Types.h"
60.24 -#include "../TypeManager.h"
60.25 -#include "../Strings.h"
60.26 -#include "../Environments.h"
60.27 -#include "../Structures.h"
60.28 -#include "CompileContext.h"
60.29 -#include "Scopes.h"
60.30 -#include "../Spaces-inl.h"
60.31 -#include "../Heap-inl.h"
60.32 -
60.33 -using namespace ke;
60.34 -
60.35 -Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
60.36 - : pool_(pool),
60.37 - kind_(kind),
60.38 - enclosing_(enclosing)
60.39 -{
60.40 -}
60.41 -
60.42 -bool
60.43 -Scope::initialize()
60.44 -{
60.45 - if (enclosing_ && !enclosing_->children_.append(this))
60.46 - return false;
60.47 - return true;
60.48 -}
60.49 -
60.50 -void
60.51 -Scope::unlink()
60.52 -{
60.53 - assert(empty());
60.54 -
60.55 - assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
60.56 - enclosing_->children_.pop();
60.57 -
60.58 - // OOM here is swallowed and checked after compilation.
60.59 - // :TODO: make the above true.
60.60 - for (size_t i = 0; i < children_.length(); i++)
60.61 - enclosing_->children_.append(children_[i]);
60.62 -}
60.63 -
60.64 -Scope *
60.65 -Scope::unlinkIfEmpty()
60.66 -{
60.67 - if (empty()) {
60.68 - unlink();
60.69 - return NULL;
60.70 - }
60.71 - return this;
60.72 -}
60.73 -
60.74 -Symbol *
60.75 -Scope::localLookup(Handle<String> name)
60.76 -{
60.77 - for (size_t i = 0; i < names_.length(); i++) {
60.78 - if (names_[i]->name() == name)
60.79 - return names_[i];
60.80 - }
60.81 - return NULL;
60.82 -}
60.83 -
60.84 -Symbol *
60.85 -Scope::lookup(Handle<String> name)
60.86 -{
60.87 - for (Scope *scope = this; scope; scope = scope->enclosing()) {
60.88 - if (Symbol *bound = scope->localLookup(name))
60.89 - return bound;
60.90 - }
60.91 - return NULL;
60.92 -}
60.93 -
60.94 -#if 0
60.95 -void
60.96 -Scope::setUsesLifoHeap()
60.97 -{
60.98 - // Only one lifo slot is needed per scope.
60.99 -#if 0
60.100 - if (lifoSlot_)
60.101 - return;
60.102 -#endif
60.103 -
60.104 - // If the parent of this scope is the function scope, then this is the
60.105 - // function's block scope, and the lifo slot is part of the Frame instead.
60.106 - // Note we can get a function scope here if we're making a temporary in a
60.107 - // function with no local variables.
60.108 - if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
60.109 - return;
60.110 -
60.111 - Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
60.112 - if (!type)
60.113 - return;
60.114 -
60.115 - Local<String> name(ZONE());
60.116 -#if 0
60.117 - lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
60.118 - lifoSlot_->setType(type);
60.119 -#endif
60.120 -}
60.121 -#endif
60.122 -
60.123 -bool
60.124 -Scope::addSymbol(Symbol *sym)
60.125 -{
60.126 - return names_.append(sym);
60.127 -}
60.128 -
60.129 -LocalScope::LocalScope(PoolAllocator &pool)
60.130 - : Scope(pool, Scope::BLOCK, NULL)
60.131 -{
60.132 -}
60.133 -
60.134 -LocalScope *
60.135 -LocalScope::New(PoolAllocator &pool)
60.136 -{
60.137 - LocalScope *scope = new (pool) LocalScope(pool);
60.138 - if (!scope->initialize())
60.139 - return NULL;
60.140 -
60.141 - return scope;
60.142 -}
60.143 -
60.144 -ArgumentScope::ArgumentScope(PoolAllocator &pool)
60.145 - : Scope(pool, Scope::FUNCTION, NULL)
60.146 -{
60.147 -}
60.148 -
60.149 -ArgumentScope *
60.150 -ArgumentScope::New(PoolAllocator &pool)
60.151 -{
60.152 - ArgumentScope *scope = new (pool) ArgumentScope(pool);
60.153 - if (!scope->initialize())
60.154 - return NULL;
60.155 -
60.156 - return scope;
60.157 -}
60.158 -
60.159 -GlobalScope::GlobalScope(PoolAllocator &pool, ImportScope *parent)
60.160 - : Scope(pool, Scope::GLOBAL, parent)
60.161 -{
60.162 -}
60.163 -
60.164 -GlobalScope *
60.165 -GlobalScope::New(PoolAllocator &pool, ImportScope *parent)
60.166 -{
60.167 - GlobalScope *scope = new (pool) GlobalScope(pool, parent);
60.168 - if (!scope->initialize())
60.169 - return NULL;
60.170 -
60.171 - return scope;
60.172 -}
60.173 -
60.174 -Symbol *
60.175 -GlobalScope::findExported(Handle<String> name)
60.176 -{
60.177 - for (size_t i = 0; i < exported_.length(); i++) {
60.178 - if (exported_[i]->name() == name)
60.179 - return exported_[i];
60.180 - }
60.181 - return NULL;
60.182 -}
60.183 -
60.184 -ImportScope::ImportScope(PoolAllocator &pool)
60.185 - : Scope(pool, Scope::IMPORT, NULL)
60.186 -{
60.187 -}
60.188 -
60.189 -ImportScope *
60.190 -ImportScope::New(PoolAllocator &pool)
60.191 -{
60.192 - ImportScope *scope = new (pool) ImportScope(pool);
60.193 - if (!scope->initialize())
60.194 - return NULL;
60.195 -
60.196 - return scope;
60.197 -}
60.198 +/* vim: set ts=4 sw=4 tw=99 et:
60.199 + *
60.200 + * Copyright (C) 2012 David Anderson
60.201 + *
60.202 + * This file is part of JITCraft.
60.203 + *
60.204 + * JITCraft is free software: you can redistribute it and/or modify it under
60.205 + * the terms of the GNU General Public License as published by the Free
60.206 + * Software Foundation, either version 3 of the License, or (at your option)
60.207 + * any later version.
60.208 + *
60.209 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
60.210 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
60.211 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
60.212 + *
60.213 + * You should have received a copy of the GNU General Public License along with
60.214 + * JITCraft. If not, see http://www.gnu.org/licenses/.
60.215 + */
60.216 +#include "../Zone.h"
60.217 +#include "../Types.h"
60.218 +#include "../TypeManager.h"
60.219 +#include "../Strings.h"
60.220 +#include "../Environments.h"
60.221 +#include "../Structures.h"
60.222 +#include "CompileContext.h"
60.223 +#include "Scopes.h"
60.224 +#include "../Spaces-inl.h"
60.225 +#include "../Heap-inl.h"
60.226 +
60.227 +using namespace ke;
60.228 +
60.229 +Scope::Scope(PoolAllocator &pool, Kind kind, Scope *enclosing)
60.230 + : pool_(pool),
60.231 + kind_(kind),
60.232 + enclosing_(enclosing)
60.233 +{
60.234 +}
60.235 +
60.236 +bool
60.237 +Scope::initialize()
60.238 +{
60.239 + if (enclosing_ && !enclosing_->children_.append(this))
60.240 + return false;
60.241 + return true;
60.242 +}
60.243 +
60.244 +void
60.245 +Scope::unlink()
60.246 +{
60.247 + assert(empty());
60.248 +
60.249 + assert(enclosing_->children_[enclosing_->children_.length() - 1] == this);
60.250 + enclosing_->children_.pop();
60.251 +
60.252 + // OOM here is swallowed and checked after compilation.
60.253 + // :TODO: make the above true.
60.254 + for (size_t i = 0; i < children_.length(); i++)
60.255 + enclosing_->children_.append(children_[i]);
60.256 +}
60.257 +
60.258 +Scope *
60.259 +Scope::unlinkIfEmpty()
60.260 +{
60.261 + if (empty()) {
60.262 + unlink();
60.263 + return NULL;
60.264 + }
60.265 + return this;
60.266 +}
60.267 +
60.268 +Symbol *
60.269 +Scope::localLookup(Handle<String> name)
60.270 +{
60.271 + for (size_t i = 0; i < names_.length(); i++) {
60.272 + if (names_[i]->name() == name)
60.273 + return names_[i];
60.274 + }
60.275 + return NULL;
60.276 +}
60.277 +
60.278 +Symbol *
60.279 +Scope::lookup(Handle<String> name)
60.280 +{
60.281 + for (Scope *scope = this; scope; scope = scope->enclosing()) {
60.282 + if (Symbol *bound = scope->localLookup(name))
60.283 + return bound;
60.284 + }
60.285 + return NULL;
60.286 +}
60.287 +
60.288 +#if 0
60.289 +void
60.290 +Scope::setUsesLifoHeap()
60.291 +{
60.292 + // Only one lifo slot is needed per scope.
60.293 +#if 0
60.294 + if (lifoSlot_)
60.295 + return;
60.296 +#endif
60.297 +
60.298 + // If the parent of this scope is the function scope, then this is the
60.299 + // function's block scope, and the lifo slot is part of the Frame instead.
60.300 + // Note we can get a function scope here if we're making a temporary in a
60.301 + // function with no local variables.
60.302 + if (kind() == FUNCTION || enclosing()->kind() == FUNCTION)
60.303 + return;
60.304 +
60.305 + Local<Type> type(ZONE(), ZONE()->types()->getPrimitive(PrimitiveType_Native));
60.306 + if (!type)
60.307 + return;
60.308 +
60.309 + Local<String> name(ZONE());
60.310 +#if 0
60.311 + lifoSlot_ = new (pool_) Variable(this, name, SourcePosition());
60.312 + lifoSlot_->setType(type);
60.313 +#endif
60.314 +}
60.315 +#endif
60.316 +
60.317 +bool
60.318 +Scope::addSymbol(Symbol *sym)
60.319 +{
60.320 + return names_.append(sym);
60.321 +}
60.322 +
60.323 +LocalScope::LocalScope(PoolAllocator &pool)
60.324 + : Scope(pool, Scope::BLOCK, NULL)
60.325 +{
60.326 +}
60.327 +
60.328 +LocalScope *
60.329 +LocalScope::New(PoolAllocator &pool)
60.330 +{
60.331 + LocalScope *scope = new (pool) LocalScope(pool);
60.332 + if (!scope->initialize())
60.333 + return NULL;
60.334 +
60.335 + return scope;
60.336 +}
60.337 +
60.338 +ArgumentScope::ArgumentScope(PoolAllocator &pool)
60.339 + : Scope(pool, Scope::FUNCTION, NULL)
60.340 +{
60.341 +}
60.342 +
60.343 +ArgumentScope *
60.344 +ArgumentScope::New(PoolAllocator &pool)
60.345 +{
60.346 + ArgumentScope *scope = new (pool) ArgumentScope(pool);
60.347 + if (!scope->initialize())
60.348 + return NULL;
60.349 +
60.350 + return scope;
60.351 +}
60.352 +
60.353 +GlobalScope::GlobalScope(PoolAllocator &pool, ImportScope *parent)
60.354 + : Scope(pool, Scope::GLOBAL, parent)
60.355 +{
60.356 +}
60.357 +
60.358 +GlobalScope *
60.359 +GlobalScope::New(PoolAllocator &pool, ImportScope *parent)
60.360 +{
60.361 + GlobalScope *scope = new (pool) GlobalScope(pool, parent);
60.362 + if (!scope->initialize())
60.363 + return NULL;
60.364 +
60.365 + return scope;
60.366 +}
60.367 +
60.368 +Symbol *
60.369 +GlobalScope::findExported(Handle<String> name)
60.370 +{
60.371 + for (size_t i = 0; i < exported_.length(); i++) {
60.372 + if (exported_[i]->name() == name)
60.373 + return exported_[i];
60.374 + }
60.375 + return NULL;
60.376 +}
60.377 +
60.378 +ImportScope::ImportScope(PoolAllocator &pool)
60.379 + : Scope(pool, Scope::IMPORT, NULL)
60.380 +{
60.381 +}
60.382 +
60.383 +ImportScope *
60.384 +ImportScope::New(PoolAllocator &pool)
60.385 +{
60.386 + ImportScope *scope = new (pool) ImportScope(pool);
60.387 + if (!scope->initialize())
60.388 + return NULL;
60.389 +
60.390 + return scope;
60.391 +}
61.1 --- a/src/compiler/Scopes.h Mon Jun 10 00:46:29 2013 +0100
61.2 +++ b/src/compiler/Scopes.h Mon Jun 10 01:04:43 2013 +0100
61.3 @@ -1,125 +1,125 @@
61.4 -/*
61.5 - * Copyright (C) 2012 David Anderson
61.6 - *
61.7 - * This file is part of JITCraft.
61.8 - *
61.9 - * JITCraft is free software: you can redistribute it and/or modify it under
61.10 - * the terms of the GNU General Public License as published by the Free
61.11 - * Software Foundation, either version 3 of the License, or (at your option)
61.12 - * any later version.
61.13 - *
61.14 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
61.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
61.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
61.17 - *
61.18 - * You should have received a copy of the GNU General Public License along with
61.19 - * JITCraft. If not, see http://www.gnu.org/licenses/.
61.20 - */
61.21 -#ifndef _include_jitcraft_scopes_h_
61.22 -#define _include_jitcraft_scopes_h_
61.23 -
61.24 -#include "../PoolAllocator.h"
61.25 -#include "../Structures.h"
61.26 -#include "AST.h"
61.27 -#include "NameBinding.h"
61.28 -
61.29 -namespace ke {
61.30 -
61.31 -class CompileContext;
61.32 -class EnvironmentMap;
61.33 -class Struct;
61.34 -
61.35 -class Scope : public PoolObject
61.36 -{
61.37 - protected:
61.38 - PoolAllocator &pool_;
61.39 - PoolList<Symbol *> names_;
61.40 - PoolList<Scope *> children_;
61.41 -
61.42 - bool empty() const {
61.43 - return names_.length() == 0;
61.44 - }
61.45 - void unlink();
61.46 -
61.47 - public:
61.48 - enum Kind {
61.49 - IMPORT,
61.50 - GLOBAL,
61.51 - FUNCTION,
61.52 - BLOCK
61.53 - };
61.54 -
61.55 - public:
61.56 - Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
61.57 - bool initialize();
61.58 -
61.59 - Kind kind() const {
61.60 - return kind_;
61.61 - }
61.62 - Scope *enclosing() const {
61.63 - return enclosing_;
61.64 - }
61.65 -
61.66 - bool addSymbol(Symbol *symbol);
61.67 -
61.68 - Scope *unlinkIfEmpty();
61.69 - Symbol *localLookup(Handle<String> name);
61.70 - Symbol *lookup(Handle<String> name);
61.71 -
61.72 - EnvironmentMap *createEnvironmentMap(Zone *zone);
61.73 -
61.74 - void setParent(Scope *parent) {
61.75 - assert(!enclosing_ || enclosing_ == parent);
61.76 - enclosing_ = parent;
61.77 - }
61.78 -
61.79 - private:
61.80 - Kind kind_;
61.81 - Scope *enclosing_;
61.82 -};
61.83 -
61.84 -class ArgumentScope : public Scope
61.85 -{
61.86 - public:
61.87 - static ArgumentScope *New(PoolAllocator &pool);
61.88 -
61.89 - private:
61.90 - ArgumentScope(PoolAllocator &pool);
61.91 -};
61.92 -
61.93 -class LocalScope : public Scope
61.94 -{
61.95 - public:
61.96 - static LocalScope *New(PoolAllocator &pool);
61.97 -
61.98 - private:
61.99 - LocalScope(PoolAllocator &pool);
61.100 -};
61.101 -
61.102 -class GlobalScope : public Scope
61.103 -{
61.104 - public:
61.105 - static GlobalScope *New(PoolAllocator &pool, ImportScope *parent);
61.106 -
61.107 - PoolList<Symbol *> *exported() {
61.108 - return &exported_;
61.109 - }
61.110 - Symbol *findExported(Handle<String> name);
61.111 -
61.112 - private:
61.113 - GlobalScope(PoolAllocator &pool, ImportScope *parent);
61.114 - PoolList<Symbol *> exported_;
61.115 -};
61.116 -
61.117 -class ImportScope : public Scope
61.118 -{
61.119 - public:
61.120 - static ImportScope *New(PoolAllocator &pool);
61.121 -
61.122 - private:
61.123 - ImportScope(PoolAllocator &pool);
61.124 -};
61.125 -
61.126 -}
61.127 -
61.128 -#endif // _include_jitcraft_scopes_h_
61.129 +/*
61.130 + * Copyright (C) 2012 David Anderson
61.131 + *
61.132 + * This file is part of JITCraft.
61.133 + *
61.134 + * JITCraft is free software: you can redistribute it and/or modify it under
61.135 + * the terms of the GNU General Public License as published by the Free
61.136 + * Software Foundation, either version 3 of the License, or (at your option)
61.137 + * any later version.
61.138 + *
61.139 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
61.140 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
61.141 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
61.142 + *
61.143 + * You should have received a copy of the GNU General Public License along with
61.144 + * JITCraft. If not, see http://www.gnu.org/licenses/.
61.145 + */
61.146 +#ifndef _include_jitcraft_scopes_h_
61.147 +#define _include_jitcraft_scopes_h_
61.148 +
61.149 +#include "../PoolAllocator.h"
61.150 +#include "../Structures.h"
61.151 +#include "AST.h"
61.152 +#include "NameBinding.h"
61.153 +
61.154 +namespace ke {
61.155 +
61.156 +class CompileContext;
61.157 +class EnvironmentMap;
61.158 +class Struct;
61.159 +
61.160 +class Scope : public PoolObject
61.161 +{
61.162 + protected:
61.163 + PoolAllocator &pool_;
61.164 + PoolList<Symbol *> names_;
61.165 + PoolList<Scope *> children_;
61.166 +
61.167 + bool empty() const {
61.168 + return names_.length() == 0;
61.169 + }
61.170 + void unlink();
61.171 +
61.172 + public:
61.173 + enum Kind {
61.174 + IMPORT,
61.175 + GLOBAL,
61.176 + FUNCTION,
61.177 + BLOCK
61.178 + };
61.179 +
61.180 + public:
61.181 + Scope(PoolAllocator &pool, Kind kind, Scope *enclosing);
61.182 + bool initialize();
61.183 +
61.184 + Kind kind() const {
61.185 + return kind_;
61.186 + }
61.187 + Scope *enclosing() const {
61.188 + return enclosing_;
61.189 + }
61.190 +
61.191 + bool addSymbol(Symbol *symbol);
61.192 +
61.193 + Scope *unlinkIfEmpty();
61.194 + Symbol *localLookup(Handle<String> name);
61.195 + Symbol *lookup(Handle<String> name);
61.196 +
61.197 + EnvironmentMap *createEnvironmentMap(Zone *zone);
61.198 +
61.199 + void setParent(Scope *parent) {
61.200 + assert(!enclosing_ || enclosing_ == parent);
61.201 + enclosing_ = parent;
61.202 + }
61.203 +
61.204 + private:
61.205 + Kind kind_;
61.206 + Scope *enclosing_;
61.207 +};
61.208 +
61.209 +class ArgumentScope : public Scope
61.210 +{
61.211 + public:
61.212 + static ArgumentScope *New(PoolAllocator &pool);
61.213 +
61.214 + private:
61.215 + ArgumentScope(PoolAllocator &pool);
61.216 +};
61.217 +
61.218 +class LocalScope : public Scope
61.219 +{
61.220 + public:
61.221 + static LocalScope *New(PoolAllocator &pool);
61.222 +
61.223 + private:
61.224 + LocalScope(PoolAllocator &pool);
61.225 +};
61.226 +
61.227 +class GlobalScope : public Scope
61.228 +{
61.229 + public:
61.230 + static GlobalScope *New(PoolAllocator &pool, ImportScope *parent);
61.231 +
61.232 + PoolList<Symbol *> *exported() {
61.233 + return &exported_;
61.234 + }
61.235 + Symbol *findExported(Handle<String> name);
61.236 +
61.237 + private:
61.238 + GlobalScope(PoolAllocator &pool, ImportScope *parent);
61.239 + PoolList<Symbol *> exported_;
61.240 +};
61.241 +
61.242 +class ImportScope : public Scope
61.243 +{
61.244 + public:
61.245 + static ImportScope *New(PoolAllocator &pool);
61.246 +
61.247 + private:
61.248 + ImportScope(PoolAllocator &pool);
61.249 +};
61.250 +
61.251 +}
61.252 +
61.253 +#endif // _include_jitcraft_scopes_h_
62.1 --- a/src/compiler/SemanticAnalysis.cpp Mon Jun 10 00:46:29 2013 +0100
62.2 +++ b/src/compiler/SemanticAnalysis.cpp Mon Jun 10 01:04:43 2013 +0100
62.3 @@ -1,1423 +1,1423 @@
62.4 -/* vim: set ts=4 sw=4 tw=99 et:
62.5 - *
62.6 - * Copyright (C) 2012 David Anderson
62.7 - *
62.8 - * This file is part of SourcePawn.
62.9 - *
62.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
62.11 - * the terms of the GNU General Public License as published by the Free
62.12 - * Software Foundation, either version 3 of the License, or (at your option)
62.13 - * any later version.
62.14 - *
62.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
62.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
62.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
62.18 - *
62.19 - * You should have received a copy of the GNU General Public License along with
62.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
62.21 - */
62.22 -#include <assert.h>
62.23 -#include "../Zone.h"
62.24 -#include "../Strings.h"
62.25 -#include "../NativeTable.h"
62.26 -#include "../TypeManager.h"
62.27 -#include "../Modules.h"
62.28 -#include "../Code.h"
62.29 -#include "SemanticAnalysis.h"
62.30 -#include "../Heap-inl.h"
62.31 -
62.32 -using namespace ke;
62.33 -
62.34 -#define __ emitter_.
62.35 -
62.36 -typedef BytecodeEmitter::Label Label;
62.37 -
62.38 -class AutoEnterScope
62.39 -{
62.40 - public:
62.41 - AutoEnterScope(Scope **prevp, Scope *scope)
62.42 - : prevp_(prevp),
62.43 - prev_(*prevp),
62.44 - scope_(scope)
62.45 - {
62.46 - if (!scope_)
62.47 - return;
62.48 - prev_ = *prevp_;
62.49 - *prevp_ = scope;
62.50 - assert(prev_ == scope->enclosing());
62.51 - }
62.52 - ~AutoEnterScope()
62.53 - {
62.54 - if (scope_)
62.55 - *prevp_ = prev_;
62.56 - }
62.57 - private:
62.58 - Scope **prevp_;
62.59 - Scope *prev_;
62.60 - Scope *scope_;
62.61 -};
62.62 -
62.63 -SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit)
62.64 - : zone_(zone),
62.65 - pool_(zone->pool()),
62.66 - cc_(cc),
62.67 - unit_(unit),
62.68 - hir_(NULL),
62.69 - loop_(NULL)
62.70 -{
62.71 -}
62.72 -
62.73 -SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun)
62.74 - : zone_(parent->zone_),
62.75 - pool_(parent->pool_),
62.76 - cc_(parent->cc_),
62.77 - unit_(parent->unit_),
62.78 - hir_(NULL),
62.79 - scope_(parent->scope_),
62.80 - fun_(fun),
62.81 - loop_(NULL),
62.82 - control_(NULL)
62.83 -{
62.84 -
62.85 -}
62.86 -
62.87 -void
62.88 -SemanticAnalysis::analyze()
62.89 -{
62.90 - scope_ = unit_->globalScope();
62.91 -
62.92 - for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
62.93 - Statement *stmt = unit_->tree()->statements()->at(i);
62.94 - stmt->accept(this);
62.95 - }
62.96 -
62.97 - Local<Code> code(zone_, __ finish());
62.98 - if (!code)
62.99 - return;
62.100 - code->setModule(unit_->module());
62.101 - unit_->module()->setCode(code);
62.102 -
62.103 -#ifndef NDEBUG
62.104 -// Disassemble(code, stdout);
62.105 -#endif
62.106 -}
62.107 -
62.108 -void
62.109 -SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt)
62.110 -{
62.111 - FunctionSymbol *sym = stmt->sym();
62.112 - Local<FunctionType> type(zone_, sym->type());
62.113 -
62.114 - assert(scope_->kind() == Scope::GLOBAL);
62.115 -
62.116 - if (stmt->token() == TOK_NATIVE) {
62.117 - // Define the native now.
62.118 - size_t index;
62.119 - if (!zone_->nativeTable()->add(stmt->name(), &index))
62.120 - return;
62.121 -
62.122 - Local<Native> native(zone_, Native::New(zone_, type, index));
62.123 - if (!native)
62.124 - return;
62.125 -
62.126 - __ object(native);
62.127 - __ setglobal(sym);
62.128 - __ pop();
62.129 - }
62.130 -
62.131 - // If the function is a forward or native, we don't have to do anything.
62.132 - if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD)
62.133 - return;
62.134 -
62.135 - SemanticAnalysis child(this, type);
62.136 - Local<Function> funobj(zone_, child.compile(stmt));
62.137 - if (!funobj)
62.138 - return;
62.139 -
62.140 - __ object(funobj);
62.141 - __ setglobal(sym);
62.142 - if (stmt->token() == TOK_PUBLIC)
62.143 - __ public_();
62.144 - else
62.145 - __ pop();
62.146 -}
62.147 -
62.148 -Function *
62.149 -SemanticAnalysis::compile(FunctionStatement *stmt)
62.150 -{
62.151 - __ setFirstLine(stmt->pos().line);
62.152 -
62.153 - AutoEnterScope argScope(&scope_, stmt->argScope());
62.154 -
62.155 - for (size_t i = 0; i < stmt->signature().parameters()->length(); i++) {
62.156 - Parameter *param = stmt->signature().parameters()->at(i);
62.157 - param->sym()->allocate(VariableSymbol::Arg, i);
62.158 - }
62.159 -
62.160 - AutoEnterScope varScope(&scope_, stmt->varScope());
62.161 - ControlStatus status = visitForControl(stmt->body());
62.162 -
62.163 - if (!fun_->returnType()->isVoid()) {
62.164 - // If the function is not void, report if not all paths return a value.
62.165 - // All other incorrect return cases have been caught already.
62.166 - if (status.returns() == Returns_Sometimes) {
62.167 - cc_.reportError(stmt->pos(), Message_NotAllPathsReturnValue);
62.168 - return NULL;
62.169 - }
62.170 -
62.171 - if (status.returns() == Returns_Never) {
62.172 - cc_.reportError(stmt->pos(), Message_MissingReturnValue);
62.173 - return NULL;
62.174 - }
62.175 - }
62.176 -
62.177 - Local<Code> code(zone_, __ finish());
62.178 - if (!code)
62.179 - return NULL;
62.180 - code->setModule(unit_->module());
62.181 -
62.182 - Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
62.183 - if (!fun)
62.184 - return NULL;
62.185 -
62.186 -#ifndef NDEBUG
62.187 -// Disassemble(code, stdout);
62.188 -#endif
62.189 -
62.190 - return fun;
62.191 -}
62.192 -
62.193 -void
62.194 -SemanticAnalysis::visitBlockStatement(BlockStatement *node)
62.195 -{
62.196 - AutoEnterScope scope(&scope_, node->scope());
62.197 -
62.198 - for (size_t i = 0; i < node->statements()->length(); i++) {
62.199 - Statement *stmt = node->statements()->at(i);
62.200 - __ note_position(stmt->pos());
62.201 - stmt->accept(this);
62.202 - assert(__ stackDepth() == 0);
62.203 - }
62.204 -}
62.205 -
62.206 -void
62.207 -SemanticAnalysis::visitEnumStatement(EnumStatement *node)
62.208 -{
62.209 -}
62.210 -
62.211 -void
62.212 -SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node)
62.213 -{
62.214 - // While building HIR, we enter new pool and root scopes, since HIR
62.215 - // creation is purely temporary.
62.216 - PoolScope poolScope(zone_->pool());
62.217 - RootScope rootScope(zone_);
62.218 -
62.219 - HIR *hir = eval(node->expression());
62.220 - if (!hir)
62.221 - return;
62.222 -
62.223 - discharge(hir);
62.224 - if (!hir->type()->isVoid())
62.225 - __ pop();
62.226 -}
62.227 -
62.228 -void
62.229 -SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
62.230 -{
62.231 - // If both sides terminate in a return, we consider this a return as well.
62.232 - if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
62.233 - terminate(Returns_Always);
62.234 - return;
62.235 - }
62.236 -
62.237 - ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
62.238 - ? Returns_Never
62.239 - : Returns_Sometimes;
62.240 -
62.241 - if (left.terminates() && right.terminates())
62.242 - terminate(status);
62.243 - else
62.244 - returns(status);
62.245 -}
62.246 -
62.247 -SemanticAnalysis::ControlStatus
62.248 -SemanticAnalysis::visitForControl(Statement *statement)
62.249 -{
62.250 - ControlScope scope(&control_);
62.251 - statement->accept(this);
62.252 - return scope.status();
62.253 -}
62.254 -
62.255 -void
62.256 -SemanticAnalysis::visitIfStatement(IfStatement *node)
62.257 -{
62.258 - Label join;
62.259 -
62.260 - ControlStatus trueBranch;
62.261 - ControlStatus falseBranch(false, Returns_Never);
62.262 -
62.263 - if (!node->ifFalse()) {
62.264 - Label success;
62.265 -
62.266 - visitForTest(node->condition(), &success, &join, &success);
62.267 - __ bind(&success);
62.268 - trueBranch = visitForControl(node->ifTrue());
62.269 - } else {
62.270 - Label success, next;
62.271 -
62.272 - visitForTest(node->condition(), &success, &next, &success);
62.273 - __ bind(&success);
62.274 - trueBranch = visitForControl(node->ifTrue());
62.275 - __ jump(&join);
62.276 - __ bind(&next);
62.277 - falseBranch = visitForControl(node->ifFalse());
62.278 - }
62.279 -
62.280 - __ bind(&join);
62.281 -
62.282 - control_->merge(trueBranch, falseBranch);
62.283 -}
62.284 -
62.285 -void
62.286 -SemanticAnalysis::requireLifoStack()
62.287 -{
62.288 - if (!loop_)
62.289 - return;
62.290 -
62.291 - loop_->setUsesLifoStack();
62.292 -}
62.293 -
62.294 -SemanticAnalysis::ControlStatus
62.295 -SemanticAnalysis::visitLoopBody(Statement *stmt)
62.296 -{
62.297 - // We always mark off a loop body, so on each edge, we can balance the
62.298 - // LIFO stack. Right now, we don't have the ability to budget the LIFO
62.299 - // stack ahead of time. If we turn out to never need the LIFO stack, we
62.300 - // mark it as unnecessary. (The interpreter can't really make use of this,
62.301 - // but the JIT can).
62.302 - //
62.303 - // Note that balancing the LIFO stack isn't even necessary, so this
62.304 - // feature may be removed. All this mechanism does is mitigate the
62.305 - // possibility that a long-running loop will overflow the LIFO region
62.306 - // and therefore start requiring nursery allocations.
62.307 - int pos = __ enterloop();
62.308 - ControlStatus status = visitForControl(stmt);
62.309 - __ leaveloop();
62.310 -
62.311 - if (loop_->usesLifoStack())
62.312 - __ setLoopUsesLifoStack(pos);
62.313 -
62.314 - return status;
62.315 -}
62.316 -
62.317 -void
62.318 -SemanticAnalysis::visitForStatement(ForStatement *node)
62.319 -{
62.320 - AutoEnterScope scope(&scope_, node->scope());
62.321 - PoolScope poolScope(zone_->pool());
62.322 - RootScope rootScope(zone_);
62.323 -
62.324 - Label join, update;
62.325 - LoopScope loop(scope_, &join, &update, &loop_);
62.326 -
62.327 - if (node->initialization())
62.328 - node->initialization()->accept(this);
62.329 -
62.330 - Label header, test;
62.331 - if (node->condition())
62.332 - __ jump(&test);
62.333 -
62.334 - __ bind(&header);
62.335 - ControlStatus status = visitLoopBody(node->body());
62.336 -
62.337 - __ bind(&update);
62.338 - if (node->update())
62.339 - node->update()->accept(this);
62.340 -
62.341 - if (node->condition()) {
62.342 - __ bind(&test);
62.343 - visitForTest(node->condition(), &header, &join, &join);
62.344 - } else {
62.345 - __ jump(&header);
62.346 - }
62.347 -
62.348 - __ bind(&join);
62.349 -
62.350 - // If there was a condition, we treat this like a while loop. Otherwise,
62.351 - // the join point is only reachable if the loop contains a break. The
62.352 - // termination status doesn't tell us anything yet.
62.353 - if (node->condition() || loop.breaks())
62.354 - control_->merge(status, ControlStatus(false, Returns_Never));
62.355 - else
62.356 - control_->terminate(status.returns());
62.357 -
62.358 - assert(__ stackDepth() == 0);
62.359 -}
62.360 -
62.361 -void
62.362 -SemanticAnalysis::visitWhileStatement(WhileStatement *node)
62.363 -{
62.364 - PoolScope poolScope(zone_->pool());
62.365 - RootScope rootScope(zone_);
62.366 -
62.367 - Label header, join;
62.368 -
62.369 - __ bind(&header);
62.370 -
62.371 - ControlStatus status;
62.372 -
62.373 - LoopScope loop(scope_, &join, &header, &loop_);
62.374 - if (node->token() == TOK_WHILE) {
62.375 - Label body;
62.376 - visitForTest(node->condition(), &body, &join, &body);
62.377 - status = visitLoopBody(node->body());
62.378 - __ jump(&header);
62.379 - } else {
62.380 - status = visitLoopBody(node->body());
62.381 - visitForTest(node->condition(), &header, &join, &join);
62.382 - }
62.383 -
62.384 - __ bind(&join);
62.385 -
62.386 - // Detect loops that will always have a fork in the contro-flow graph.
62.387 - // This will be a |while| loop, or a |do-while| loop whose body does
62.388 - // not terminate. For now, we treat these as an |if| regardless of the
62.389 - // direction the branch can take. That means the control-flow is always
62.390 - // conditional.
62.391 - if (node->token() == TOK_WHILE || status.terminates() || loop.breaks()) {
62.392 - control_->merge(status, ControlStatus(false, Returns_Never));
62.393 - } else {
62.394 - // At this point, we've got a do-while loop with a |return| or
62.395 - // |continue|, meaning that the rest of the block is unreachable.
62.396 - control_->terminate(status.returns());
62.397 - }
62.398 -
62.399 - assert(__ stackDepth() == 0);
62.400 -}
62.401 -
62.402 -static inline Heap::Tenure
62.403 -InferTenure(Symbol *sym)
62.404 -{
62.405 - if (sym->scope()->kind() == Scope::GLOBAL)
62.406 - return Heap::Tenure_Old;
62.407 -
62.408 - // SP2's array semantics allow any array kind to escape, so we must use
62.409 - // the normal heap. (Hopefully escape analysis can ease this pain later).
62.410 - if (sym->type()->isArray())
62.411 - return Heap::Tenure_Default;
62.412 -
62.413 - return Heap::Tenure_Default;
62.414 -}
62.415 -
62.416 -void
62.417 -SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
62.418 -{
62.419 - PoolScope poolScope(zone_->pool());
62.420 - RootScope rootScope(zone_);
62.421 -
62.422 - Local<Type> type(zone_, node->sym()->type());
62.423 -
62.424 - if (node->sym()->type()->isVoid()) {
62.425 - cc_.reportError(node->type()->pos(), Message_CannotDeclareVoid);
62.426 - return;
62.427 - }
62.428 -
62.429 - if (node->initialization()) {
62.430 - HIR *hir = NULL;
62.431 -
62.432 - if ((hir = eval(node->initialization())) == NULL)
62.433 - return;
62.434 - if ((hir = coerce(hir, type, Coerce_Decl)) == NULL)
62.435 - return;
62.436 -
62.437 - discharge(hir);
62.438 - } else {
62.439 - if (type->isInt32() || type->isEnum() ||
62.440 - type->isChar() || type->isBool())
62.441 - {
62.442 - __ int_(0);
62.443 - } else if (type->isFloat()) {
62.444 - __ float_(0);
62.445 - } else if (type->isArray()) {
62.446 - Local<ArrayType> atype(zone_, ArrayType::cast(type));
62.447 - Local<ArrayMap> map(zone_, atype->newMap());
62.448 - if (!map)
62.449 - return;
62.450 -
62.451 - if (atype->isFixedLength()) {
62.452 - __ newarray(OP_NEWFIXED, map, InferTenure(node->sym()));
62.453 - } else if (node->dims()->at(0)) {
62.454 - // This may not be true if we allow typedefing, so :TODO:
62.455 - // figure out proper semantics.
62.456 - assert(node->dims()->length() == atype->levels());
62.457 -
62.458 - Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.459 - for (size_t i = 0; i < node->dims()->length(); i++) {
62.460 - Expression *expr = node->dims()->at(i);
62.461 - if (expr) {
62.462 - HIR *hir = eval(expr);
62.463 - if (!hir || ((hir = coerce(hir, i32, Coerce_Arg)) == NULL))
62.464 - return;
62.465 - discharge(hir);
62.466 - } else {
62.467 - __ int_(0);
62.468 - }
62.469 - }
62.470 - __ newarray(OP_NEWSIZED, map, InferTenure(node->sym()));
62.471 - } else {
62.472 - __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym()));
62.473 - }
62.474 - } else {
62.475 - assert(false);
62.476 - }
62.477 - }
62.478 -
62.479 - if (node->sym()->scope()->kind() != Scope::GLOBAL) {
62.480 - if (!__ allocate(node->sym()))
62.481 - return;
62.482 - }
62.483 -
62.484 - set(node->sym());
62.485 - __ pop();
62.486 -}
62.487 -
62.488 -void
62.489 -SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
62.490 -{
62.491 - control_->returns(Returns_Always);
62.492 -
62.493 - if (!node->expression()) {
62.494 - if (!fun_->returnType()->isVoid()) {
62.495 - cc_.reportError(node->pos(), Message_MissingReturnValue);
62.496 - return;
62.497 - }
62.498 -
62.499 - __ returnvoid();
62.500 - return;
62.501 - }
62.502 -
62.503 - if (fun_->returnType()->isVoid()) {
62.504 - cc_.reportError(node->pos(), Message_UsedVoidReturn);
62.505 - return;
62.506 - }
62.507 -
62.508 - PoolScope poolScope(zone_->pool());
62.509 - RootScope rootScope(zone_);
62.510 -
62.511 - HIR *hir = eval(node->expression());
62.512 - if (!hir)
62.513 - return;
62.514 -
62.515 - Local<Type> returnType(zone_, fun_->returnType());
62.516 - if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL)
62.517 - return;
62.518 -
62.519 - discharge(hir);
62.520 -
62.521 - if (hir->type()->isVoid())
62.522 - __ returnvoid();
62.523 - else
62.524 - __ return_();
62.525 -}
62.526 -
62.527 -void
62.528 -SemanticAnalysis::visitBinaryExpression(BinaryExpression *node)
62.529 -{
62.530 - HIR *left = eval(node->left());
62.531 - HIR *right = eval(node->right());
62.532 - if (!left || !right)
62.533 - return;
62.534 -
62.535 - hir_ = binary(node, node->token(), left, right);
62.536 -}
62.537 -
62.538 -bool
62.539 -SemanticAnalysis::checkArgumentCount(Handle<FunctionType> type, unsigned actual)
62.540 -{
62.541 - if (type->parameters()->length() == actual)
62.542 - return true;
62.543 -
62.544 - if (actual > type->parameters()->length()) {
62.545 - if (!type->isNative() || !type->isNativeVariadic())
62.546 - return false;
62.547 - return true;
62.548 - }
62.549 -
62.550 - if (!type->defaults())
62.551 - return false;
62.552 -
62.553 - // Missing arguments. See if there's a default argument for each missing
62.554 - // actual.
62.555 - for (unsigned i = actual; i < type->parameters()->length(); i++) {
62.556 - if (!type->defaults()->at(i))
62.557 - return false;
62.558 - }
62.559 -
62.560 - return true;
62.561 -}
62.562 -
62.563 -static unsigned
62.564 -BindImplicitName(Module *from, ImplicitSymbol *sym)
62.565 -{
62.566 - if (sym->bound())
62.567 - return sym->fieldIndex();
62.568 -
62.569 - Module *module = Module::cast(from->getImportAt(sym->index()));
62.570 - StructMap *map = module->globals()->map();
62.571 -
62.572 - unsigned fieldIndex;
62.573 - Descriptor *desc = map->type()->lookupField(sym->name(), &fieldIndex);
62.574 - assert(desc && desc->type() == sym->type());
62.575 -
62.576 - sym->bind(fieldIndex);
62.577 - return fieldIndex;
62.578 -}
62.579 -
62.580 -void
62.581 -SemanticAnalysis::visitNameProxy(NameProxy *proxy)
62.582 -{
62.583 - Symbol *sym = proxy->sym();
62.584 -
62.585 - switch (sym->kind()) {
62.586 - case Symbol::kImport:
62.587 - {
62.588 - ImportSymbol *import = sym->toImport();
62.589 - hir_ = new (pool_) HImport(proxy, sym->type(), import->index());
62.590 - break;
62.591 - }
62.592 -
62.593 - case Symbol::kImplicit:
62.594 - {
62.595 - ImplicitSymbol *import = sym->toImplicit();
62.596 - unsigned fieldIndex = BindImplicitName(unit_->module(), import);
62.597 -
62.598 - hir_ = new (pool_) HImport(proxy, zone_->types()->getImportable(), import->index());
62.599 - hir_ = new (pool_) HField(proxy, hir_, sym->type(), fieldIndex);
62.600 - break;
62.601 - }
62.602 -
62.603 - case Symbol::kConstant:
62.604 - {
62.605 - ConstantSymbol *val = sym->toConstant();
62.606 - hir_ = new (pool_) HInteger(proxy, sym->type(), val->value().toInt());
62.607 - break;
62.608 - }
62.609 -
62.610 - // This is kind of screwy. Symbol::kFunction is like a constant we can't
62.611 - // evaluate yet. Maybe we should extract the GLOBAL case and say that
62.612 - // kFunction is only used for global functions (and use const vars for
62.613 - // local functions).
62.614 - case Symbol::kFunction:
62.615 - case Symbol::kVariable:
62.616 - {
62.617 - Scope *in = sym->scope();
62.618 - switch (in->kind()) {
62.619 - case Scope::GLOBAL:
62.620 - hir_ = new (pool_) HGlobal(proxy, sym);
62.621 - break;
62.622 -
62.623 - case Scope::FUNCTION:
62.624 - {
62.625 - VariableSymbol *var = sym->toVariable();
62.626 - assert(var->storage() == VariableSymbol::Arg);
62.627 - hir_ = new (pool_) HLocal(proxy, var);
62.628 - break;
62.629 - }
62.630 -
62.631 - default:
62.632 - {
62.633 - VariableSymbol *var = sym->toVariable();
62.634 - assert(in->kind() == Scope::BLOCK);
62.635 - assert(var->storage() == VariableSymbol::Local);
62.636 - hir_ = new (pool_) HLocal(proxy, var);
62.637 - break;
62.638 - }
62.639 - }
62.640 - break;
62.641 - }
62.642 -
62.643 - default:
62.644 - // :TODO:
62.645 - assert(false);
62.646 - }
62.647 -}
62.648 -
62.649 -void
62.650 -SemanticAnalysis::visitBooleanLiteral(BooleanLiteral *node)
62.651 -{
62.652 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
62.653 - hir_ = new (pool_) HBoolean(node, type, node->token() == TOK_TRUE);
62.654 -}
62.655 -
62.656 -void
62.657 -SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit)
62.658 -{
62.659 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.660 - hir_ = new (pool_) HInteger(lit, type, lit->value());
62.661 -}
62.662 -
62.663 -void
62.664 -SemanticAnalysis::visitFloatLiteral(FloatLiteral *node)
62.665 -{
62.666 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
62.667 - hir_ = new (pool_) HFloat(node, type, (float)node->value());
62.668 -}
62.669 -
62.670 -void
62.671 -SemanticAnalysis::visitStringLiteral(StringLiteral *node)
62.672 -{
62.673 - Type *type = zone_->types()->getString();
62.674 - hir_ = new (pool_) HString(node, type, node->string());
62.675 -}
62.676 -
62.677 -void
62.678 -SemanticAnalysis::visitCallExpression(CallExpression *node)
62.679 -{
62.680 - HIR *callee = eval(node->callee());
62.681 - if (!callee)
62.682 - return;
62.683 -
62.684 - if (!callee->type()->isFunction()) {
62.685 - cc_.reportError(node->pos(), Message_CalleeNotFunction);
62.686 - return;
62.687 - }
62.688 -
62.689 - Local<FunctionType> fun(zone_, FunctionType::cast(callee->type()));
62.690 -
62.691 - if (!checkArgumentCount(fun, node->arguments()->length())) {
62.692 - cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
62.693 - return;
62.694 - }
62.695 -
62.696 - if (fun->isForward()) {
62.697 - cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
62.698 - return;
62.699 - }
62.700 -
62.701 - HIRList *args = new (pool_) HIRList;
62.702 - for (unsigned i = 0; i < node->arguments()->length(); i++) {
62.703 - Expression *expression = node->arguments()->at(i);
62.704 - HIR *arg = eval(expression);
62.705 - if (!arg)
62.706 - return;
62.707 -
62.708 - Handle<Type> given = arg->type();
62.709 -
62.710 - bool mustComputeReference;
62.711 - if (i >= fun->parameters()->length()) {
62.712 - // Special handling for natives. Arguments past the formal must
62.713 - // always have references computed. However, arrays are already
62.714 - // references for natives.
62.715 - assert(fun->isNative() && fun->isNativeVariadic());
62.716 - mustComputeReference = !given->isReference() &&
62.717 - !given->isArray();
62.718 - } else {
62.719 - Local<Type> actual(zone_, fun->parameterAt(i));
62.720 -
62.721 - if (expression->isIndexExpression() && arg->isIndex()) {
62.722 - // If the expression is the form x[y], and this produced a
62.723 - // normal array indexing operation, then we apply some
62.724 - // special rules.
62.725 -
62.726 - if (actual->isReference()) {
62.727 - // Disabled, since this doesn't have easily definable or
62.728 - // sensible semantics with SP2 arrays, but we don't want
62.729 - // to silently break SP1 semantics.
62.730 - cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
62.731 - return;
62.732 - }
62.733 -
62.734 - // As a special rule to account for SP1 semantics, we allow x[y]
62.735 - // to automatically compute a sliced, read-only array view if
62.736 - // the desired type is an array of one more dimension than x[y]
62.737 - // would return.
62.738 - //
62.739 - // As an additional restriction, this is only allowed for
62.740 - // one-level char arrays, to minimize potential issues until
62.741 - // we determine whether more compatibility is needed.
62.742 - //
62.743 - // Internally, for sanity, the dependent array operation does
62.744 - // not necessarily create a dependent array. For extensible
62.745 - // arrays, we instead create a duplicate arrary of just the
62.746 - // sliced portion, rather than deal with the complexity of the
62.747 - // source array being resized.
62.748 - //
62.749 - // Note that we don't really know whether a dependent array
62.750 - // will be dependent at compile-time, so the dependent type's
62.751 - // just inherits from the source.
62.752 - if (actual->isArray()) {
62.753 - HIndex *index = arg->toIndex();
62.754 - Local<ArrayType> basetype(zone_, ArrayType::cast(index->base()->type()));
62.755 - Local<ArrayType> atype(zone_, ArrayType::cast(actual));
62.756 -
62.757 - if (atype->isCharArray() && basetype->isCharArray()) {
62.758 - // There is no possible way this will type check, so
62.759 - // it's safe to just try something completely
62.760 - // different.
62.761 - Local<Type> slicetype(zone_);
62.762 - if (basetype->isFixedLength()) {
62.763 - // If the base type is fixed length, we need to
62.764 - // compute a new dynamic array type based on the
62.765 - // fixed array's contents and qualifiers.
62.766 - Local<Type> contained(zone_, basetype->contained());
62.767 - slicetype = zone_->types()->newArray(contained, ArrayType::DYNAMIC_ARRAY_SIZE);
62.768 - if (!slicetype)
62.769 - return;
62.770 - slicetype = zone_->types()->qualify(slicetype, basetype->quals());
62.771 - if (!slicetype)
62.772 - return;
62.773 - } else {
62.774 - slicetype = basetype;
62.775 - }
62.776 - arg = new (pool_) HNewDependentArray(expression, slicetype, index->base(), index->index());
62.777 - given = arg->type();
62.778 - }
62.779 - }
62.780 - }
62.781 -
62.782 - if (actual->isReference()) {
62.783 - // If the actual is a reference, the coercion rules are much
62.784 - // stricter; the contained types must be identical.
62.785 - // :TODO: make this not an assert
62.786 - assert(ReferenceType::cast(actual)->contained() == arg->type());
62.787 - } else {
62.788 - // When we start overloading, coercion will have to happen later.
62.789 - arg = coerce(arg, actual, Coerce_Arg);
62.790 - if (!arg)
62.791 - return;
62.792 - }
62.793 -
62.794 - mustComputeReference = actual->isReference() && !given->isReference();
62.795 - }
62.796 -
62.797 - if (mustComputeReference) {
62.798 - // Refs always use the LIFO stack if they can.
62.799 - arg = new (pool_) HToRef(arg->node(), arg->type(), arg);
62.800 - requireLifoStack();
62.801 - }
62.802 -
62.803 - if (!args->append(arg))
62.804 - return;
62.805 - }
62.806 -
62.807 - hir_ = new (pool_) HCall(node, fun->returnType(), callee, args);
62.808 -}
62.809 -
62.810 -void
62.811 -SemanticAnalysis::visitAssignment(Assignment *node)
62.812 -{
62.813 - HLValue *lval = lvalue(node->lvalue());
62.814 - if (!lval)
62.815 - return;
62.816 -
62.817 - if (lval->type()->quals() & TypeQual_Const) {
62.818 - cc_.reportError(node->pos(), Message_CannotModifyConst);
62.819 - return;
62.820 - }
62.821 -
62.822 - HIR *hir = eval(node->expression());
62.823 - if (!hir)
62.824 - return;
62.825 - if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
62.826 - return;
62.827 -
62.828 - hir_ = new (pool_) HStore(node, node->token(), lval, hir);
62.829 -}
62.830 -
62.831 -void
62.832 -SemanticAnalysis::visitBreakStatement(BreakStatement *node)
62.833 -{
62.834 - if (!loop_) {
62.835 - cc_.reportError(node->pos(), Message_BreakOutsideLoop);
62.836 - return;
62.837 - }
62.838 -
62.839 - loop_->setBreaks();
62.840 - __ j(OP_BREAK, loop_->break_());
62.841 -}
62.842 -
62.843 -void
62.844 -SemanticAnalysis::visitContinueStatement(ContinueStatement *node)
62.845 -{
62.846 - if (!loop_) {
62.847 - cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
62.848 - return;
62.849 - }
62.850 -
62.851 - __ j(OP_CONTINUE, loop_->continue_());
62.852 -}
62.853 -
62.854 -void
62.855 -SemanticAnalysis::visitIndexExpression(IndexExpression *node)
62.856 -{
62.857 - HIR *left = eval(node->left());
62.858 - if (!left)
62.859 - return;
62.860 -
62.861 - HIR *right = eval(node->right());
62.862 - if (!right)
62.863 - return;
62.864 -
62.865 - // Hrm... yes, for now, let's coerce here.
62.866 - Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.867 - if ((right = coerce(right, i32, Coerce_Arg)) == NULL)
62.868 - return;
62.869 -
62.870 - // Do not coerce here, there's no reason to yet.
62.871 - if (!left->type()->isArray()) {
62.872 - cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
62.873 - return;
62.874 - }
62.875 -
62.876 - hir_ = new (pool_) HIndex(node,
62.877 - ArrayType::cast(left->type())->contained(),
62.878 - left,
62.879 - right);
62.880 -}
62.881 -
62.882 -void
62.883 -SemanticAnalysis::visitIncDecExpression(IncDecExpression *node)
62.884 -{
62.885 - HLValue *lval = lvalue(node->expression());
62.886 - if (!lval)
62.887 - return;
62.888 -
62.889 - if (!lval->type()->isInt32() && !lval->type()->isFloat()) {
62.890 - assert(false);
62.891 - return;
62.892 - }
62.893 -
62.894 - HIR *rval;
62.895 - if (lval->type()->isInt32())
62.896 - rval = new (pool_) HInteger(node, lval->type(), 1);
62.897 - else
62.898 - rval = new (pool_) HFloat(node, lval->type(), 1.0);
62.899 -
62.900 - if (node->postfix())
62.901 - hir_ = new (pool_) HPostIncDec(node, node->token(), lval, rval);
62.902 - else
62.903 - hir_ = new (pool_) HStore(node, node->token(), lval, rval);
62.904 -}
62.905 -
62.906 -Type *
62.907 -SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
62.908 -{
62.909 - Local<Type> l(zone_, left->type());
62.910 - Local<Type> r(zone_, right->type());
62.911 -
62.912 - if (l->isPod())
62.913 - l = l->unqualified();
62.914 - if (r->isPod())
62.915 - r = r->unqualified();
62.916 -
62.917 - if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
62.918 - (token >= TOK_EQUALS && token <= TOK_GE))
62.919 - {
62.920 - // We allow: [float|int32] + [float|int32]
62.921 - if (l->isFloat() && r->isInt32())
62.922 - return l;
62.923 - if (l->isInt32() && r->isFloat())
62.924 - return r;
62.925 - if (l->isInt32() && r->isInt32())
62.926 - return l;
62.927 -
62.928 - if (l->isChar() && r->isInt32())
62.929 - return r;
62.930 - if (l->isInt32() && r->isChar())
62.931 - return l;
62.932 - }
62.933 -
62.934 - // :TODO: remove
62.935 - assert(*l == *r);
62.936 -
62.937 - return left->type();
62.938 -}
62.939 -
62.940 -HIR *
62.941 -SemanticAnalysis::typeCheckArray(const SourcePosition &pos,
62.942 - HIR *from,
62.943 - Handle<ArrayType> argActual,
62.944 - CoercionKind kind)
62.945 -{
62.946 - Local<Type> argGiven(zone_, from->type());
62.947 -
62.948 - // Special case: if we receive a string literal, and this is a char array,
62.949 - // we allow a coercion.
62.950 - if (from->isString() &&
62.951 - argGiven->isString() &&
62.952 - argActual->isArray() &&
62.953 - ArrayType::cast(argActual)->isCharArray())
62.954 - {
62.955 - HString *hir = from->toString();
62.956 - Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
62.957 -
62.958 - if (actual->isFixedLength()) {
62.959 - if (hir->string()->length() + 1 > actual->fixedLength()) {
62.960 - cc_.reportError(pos, Message_ArrayAssignmentTooBig);
62.961 - return NULL;
62.962 - }
62.963 - }
62.964 -
62.965 - // Transform the string literal into an array literal. We give it the
62.966 - // type of the left-hand side. The constness of the destination type
62.967 - // will determine whether HArray duplicates it or not.
62.968 - Local<ArrayMap> map(zone_, actual->newMap());
62.969 - if (!map)
62.970 - return NULL;
62.971 -
62.972 - Local<Array> array(zone_);
62.973 - array = Array::NewString(zone_,
62.974 - map,
62.975 - hir->string()->chars(),
62.976 - hir->string()->length(),
62.977 - Heap::Tenure_Old);
62.978 - if (!array)
62.979 - return NULL;
62.980 -
62.981 - // Since we're creating a canonical copy of the char array, we have to
62.982 - // be careful that it doesn't get mutated. There are two cases where
62.983 - // we know it can't be mutated, and therefore don't need to specify
62.984 - // that it be cloned after pushing it onto the stack.
62.985 - //
62.986 - // (1) The array type is const.
62.987 - // (2) The array type is fixed-length, and the coercion is for
62.988 - // assignment, meaning it will be immediately copied.
62.989 - //
62.990 - // We treat declaration separately from assignment, since for
62.991 - // declaration we can just immediately use the cloned version.
62.992 - bool shouldDuplicate = true;
62.993 - if ((actual->quals() & TypeQual_Const) ||
62.994 - (actual->isFixedLength() && kind == Coerce_Assign))
62.995 - {
62.996 - shouldDuplicate = false;
62.997 - }
62.998 -
62.999 - return new (pool_) HArray(hir->node(), actual, array, shouldDuplicate);
62.1000 - }
62.1001 -
62.1002 - if (!argGiven->isArray()) {
62.1003 - cc_.reportError(pos, Message_ExpectedArray);
62.1004 - return NULL;
62.1005 - }
62.1006 -
62.1007 - Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
62.1008 - Local<ArrayType> given(zone_, ArrayType::cast(argGiven));
62.1009 -
62.1010 - if (actual->levels() != given->levels()) {
62.1011 - cc_.reportError(pos, Message_ArrayDimensionsMismatch);
62.1012 - return NULL;
62.1013 - }
62.1014 -
62.1015 - unsigned level = 1;
62.1016 - while (true) {
62.1017 - if (actual->isFixedLength()) {
62.1018 - if (!given->isFixedLength()) {
62.1019 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
62.1020 - return NULL;
62.1021 - }
62.1022 -
62.1023 - if (actual->isCharArray()) {
62.1024 - // String assignment can have a truncated |given|.
62.1025 - if (given->fixedLength() > actual->fixedLength()) {
62.1026 - cc_.reportError(pos, Message_ArrayAssignmentTooBig);
62.1027 - return NULL;
62.1028 - }
62.1029 - } else {
62.1030 - if (given->fixedLength() != actual->fixedLength()) {
62.1031 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
62.1032 - return NULL;
62.1033 - }
62.1034 - }
62.1035 - } else if (given->isFixedLength()) {
62.1036 - // We do not allow assignments in the form:
62.1037 - // [][] = [][Y]
62.1038 - //
62.1039 - // Otherwise, the following code could break the size guarantees
62.1040 - // of the right-hand side:
62.1041 - //
62.1042 - // new x[][5];
62.1043 - // new y[][];
62.1044 - // new z[3];
62.1045 - //
62.1046 - //
62.1047 - // y = x;
62.1048 - // y[0] = z;
62.1049 - //
62.1050 - // Now |x[0]| contains a 3-length array.
62.1051 - if (level > 1) {
62.1052 - cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
62.1053 - return NULL;
62.1054 - }
62.1055 - }
62.1056 -
62.1057 - if (!given->contained()->isArray() || !actual->contained()->isArray())
62.1058 - break;
62.1059 -
62.1060 - given = ArrayType::cast(given->contained());
62.1061 - actual = ArrayType::cast(actual->contained());
62.1062 - }
62.1063 -
62.1064 - bool givenConst = !!(given->contained()->quals() & TypeQual_Const);
62.1065 - bool actualConst = !!(actual->contained()->quals() & TypeQual_Const);
62.1066 -
62.1067 - // These arrays must contain the same innermost type.
62.1068 - if (given->contained()->unqualified() != actual->contained()->unqualified() ||
62.1069 - (givenConst && !actualConst))
62.1070 - {
62.1071 - char aname[255];
62.1072 - char gname[255];
62.1073 - cc_.reportError(pos, Message_TypeMismatch,
62.1074 - GetTypeName(argActual, aname, sizeof(aname)),
62.1075 - GetTypeName(argGiven, gname, sizeof(gname)));
62.1076 - return NULL;
62.1077 - }
62.1078 -
62.1079 - return from;
62.1080 -}
62.1081 -
62.1082 -HIR *
62.1083 -SemanticAnalysis::typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to)
62.1084 -{
62.1085 - char fname[255];
62.1086 - char tname[255];
62.1087 - cc_.reportError(pos, Message_InvalidCoercion,
62.1088 - GetTypeName(from, fname, sizeof(fname)),
62.1089 - GetTypeName(to, tname, sizeof(tname)));
62.1090 - return NULL;
62.1091 -}
62.1092 -
62.1093 -HIR *
62.1094 -SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
62.1095 -{
62.1096 - Local<Type> from(zone_, hir->type());
62.1097 -
62.1098 - // If the source is *ever* an importable, we just fail.
62.1099 - if (from->isImportable())
62.1100 - return typeFailure(hir->node()->pos(), from, to);
62.1101 -
62.1102 - if (from->isInt32() && to->isFloat())
62.1103 - return new (pool_) HConvert(hir->node(), to, OP_CVT_I2F, hir);
62.1104 - if (from->isInt32() && to->isBool())
62.1105 - return new (pool_) HConvert(hir->node(), to, OP_CVT_I2B, hir);
62.1106 -
62.1107 - if (to->isEnum() && from->unqualified() != to->unqualified())
62.1108 - return typeFailure(hir->node()->pos(), from, to);
62.1109 -
62.1110 - if (to->isArray()) {
62.1111 - Local<ArrayType> atype(zone_, ArrayType::cast(to));
62.1112 - return typeCheckArray(hir->node()->pos(), hir, atype, kind);
62.1113 - }
62.1114 -
62.1115 - return hir;
62.1116 -}
62.1117 -
62.1118 -void
62.1119 -SemanticAnalysis::set(VariableSymbol *sym)
62.1120 -{
62.1121 - if (sym->scope()->kind() == Scope::GLOBAL) {
62.1122 - __ setglobal(sym);
62.1123 - } else {
62.1124 - assert(sym->storage() == VariableSymbol::Local);
62.1125 - __ setlocal(sym);
62.1126 - }
62.1127 -}
62.1128 -
62.1129 -HIR *
62.1130 -SemanticAnalysis::binary(AstNode *node, TokenKind token, HIR *left, HIR *right)
62.1131 -{
62.1132 - Local<Type> coercion(zone_, coercionType(token, left, right));
62.1133 - if (!coercion)
62.1134 - return NULL;
62.1135 - if ((left = coerce(left, coercion, Coerce_Arg)) == NULL)
62.1136 - return NULL;
62.1137 - if ((right = coerce(right, coercion, Coerce_Arg)) == NULL)
62.1138 - return NULL;
62.1139 -
62.1140 - switch (token) {
62.1141 - case TOK_PLUS:
62.1142 - case TOK_MINUS:
62.1143 - case TOK_STAR:
62.1144 - case TOK_SLASH:
62.1145 - case TOK_PERCENT:
62.1146 - case TOK_AMPERSAND:
62.1147 - case TOK_BITOR:
62.1148 - case TOK_BITXOR:
62.1149 - case TOK_SHR:
62.1150 - case TOK_USHR:
62.1151 - case TOK_SHL:
62.1152 - return new (pool_) HBinary(node, left->type(), token, left, right);
62.1153 -
62.1154 - case TOK_EQUALS:
62.1155 - case TOK_NOTEQUALS:
62.1156 - case TOK_LT:
62.1157 - case TOK_LE:
62.1158 - case TOK_GT:
62.1159 - case TOK_GE:
62.1160 - case TOK_AND:
62.1161 - case TOK_OR:
62.1162 - {
62.1163 - Local<Type> result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
62.1164 - return new (pool_) HBinary(node, result, token, left, right);
62.1165 - }
62.1166 -
62.1167 - default:
62.1168 - assert(false);
62.1169 - return NULL;
62.1170 - }
62.1171 -}
62.1172 -
62.1173 -static inline bool
62.1174 -IsValidUncheckedType(Type *type)
62.1175 -{
62.1176 - return type->isEnum() ||
62.1177 - type->isFloat() ||
62.1178 - type->isInt32() ||
62.1179 - type->isChar() ||
62.1180 - type->isUnchecked() ||
62.1181 - type->isBool();
62.1182 -}
62.1183 -
62.1184 -void
62.1185 -SemanticAnalysis::visitUnaryExpression(UnaryExpression *node)
62.1186 -{
62.1187 - HIR *hir = eval(node->expression());
62.1188 - if (!hir)
62.1189 - return;
62.1190 -
62.1191 - switch (node->token()) {
62.1192 - case TOK_TILDE:
62.1193 - {
62.1194 - if (!hir->type()->isInt32() && !hir->type()->isEnum()) {
62.1195 - char name[255];
62.1196 - cc_.reportError(node->pos(), Message_InvalidUnaryType,
62.1197 - "~",
62.1198 - GetTypeName(hir->type(), name, sizeof(name)));
62.1199 - }
62.1200 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.1201 - hir_ = new (pool_) HUnary(node, hir->type(), TOK_TILDE, hir);
62.1202 - return;
62.1203 - }
62.1204 -
62.1205 - case TOK_MINUS:
62.1206 - {
62.1207 - if (hir->type()->isInt32() || hir->type()->isEnum()) {
62.1208 - Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.1209 - hir_ = new (pool_) HUnary(node, type, TOK_MINUS, hir);
62.1210 - return;
62.1211 - }
62.1212 - if (hir->type()->isFloat()) {
62.1213 - hir_ = new (pool_) HUnary(node, hir->type(), TOK_MINUS, hir);
62.1214 - return;
62.1215 - }
62.1216 -
62.1217 - char name[255];
62.1218 - cc_.reportError(node->pos(), Message_InvalidUnaryType,
62.1219 - "-",
62.1220 - GetTypeName(hir->type(), name, sizeof(name)));
62.1221 - break;
62.1222 - }
62.1223 -
62.1224 - default:
62.1225 - {
62.1226 - assert(node->token() == TOK_LABEL);
62.1227 -
62.1228 - TypeSymbol *sym = node->tag()->sym()->asType();
62.1229 - if (!sym) {
62.1230 - cc_.reportError(node->pos(), Message_IdentifierIsNotAType,
62.1231 - sym->name()->chars());
62.1232 - return;
62.1233 - }
62.1234 -
62.1235 - if (!IsValidUncheckedType(sym->effective())) {
62.1236 - char name[255];
62.1237 - cc_.reportError(node->pos(), Message_InvalidUncheckedCastTo,
62.1238 - GetTypeName(sym->type(), name, sizeof(name)));
62.1239 - return;
62.1240 - }
62.1241 - if (!IsValidUncheckedType(hir->type())) {
62.1242 - char name[255];
62.1243 - cc_.reportError(node->pos(), Message_InvalidUncheckedCastFrom,
62.1244 - GetTypeName(hir->type(), name, sizeof(name)));
62.1245 - return;
62.1246 - }
62.1247 -
62.1248 - hir_ = new (pool_) HUnary(node, sym->effective(), TOK_LABEL, hir);
62.1249 - break;
62.1250 - }
62.1251 - }
62.1252 -}
62.1253 -
62.1254 -void
62.1255 -SemanticAnalysis::import(HIR *hir, FieldExpression *node)
62.1256 -{
62.1257 - // Note that we don't care if the hir type is "importable", since we
62.1258 - // can only do anything if the important has a constant binding.
62.1259 - unsigned index = hir->toImport()->index();
62.1260 - Local<Importable> importable(zone_, unit_->module()->getImportAt(index));
62.1261 -
62.1262 - if (importable->isPackage()) {
62.1263 - // Look at what's already loaded and see if anything exists. We
62.1264 - // can't create stuff on-demand here since it's too late to add
62.1265 - // new translation units to the CompileContext.
62.1266 - Local<Package> package(zone_, Package::cast(importable));
62.1267 - Local<Importable> found(zone_, package->import(node->field()));
62.1268 - if (!found) {
62.1269 - cc_.reportError(node->pos(), Message_PackageDoesNotHaveMember, node->field()->chars());
62.1270 - return;
62.1271 - }
62.1272 -
62.1273 - // If we did find something, make sure it is in our import list.
62.1274 - // If we didn't explicitly import it, we have no right to use it.
62.1275 - for (index = 0; index < unit_->module()->imports(); index++) {
62.1276 - if (unit_->module()->getImportAt(index) == importable)
62.1277 - break;
62.1278 - }
62.1279 -
62.1280 - if (index == unit_->module()->imports()) {
62.1281 - cc_.reportError(node->pos(), Message_ImportWasNeverImported, node->field()->chars());
62.1282 - return;
62.1283 - }
62.1284 -
62.1285 - // Just create a new HImport.
62.1286 - hir_ = new (pool_) HImport(node, hir->type(), index);
62.1287 - } else {
62.1288 - // Modules can never have sub-modules or sub-packages.
62.1289 - unsigned index;
62.1290 - Local<Module> module(zone_, Module::cast(importable));
62.1291 - Local<StructMap> map(zone_, module->globals()->map());
62.1292 - Local<Descriptor> desc(zone_, map->type()->lookupField(node->field(), &index));
62.1293 - if (!desc) {
62.1294 - cc_.reportError(node->pos(), Message_FieldNotFound, node->field()->chars());
62.1295 - return;
62.1296 - }
62.1297 - hir_ = new (pool_) HField(node, hir, desc->type(), index);
62.1298 - }
62.1299 -}
62.1300 -
62.1301 -void
62.1302 -SemanticAnalysis::visitFieldExpression(FieldExpression *node)
62.1303 -{
62.1304 - HIR *hir = eval(node->left());
62.1305 - if (!hir)
62.1306 - return;
62.1307 -
62.1308 - if (hir->isImport()) {
62.1309 - import(hir, node);
62.1310 - return;
62.1311 - }
62.1312 -
62.1313 - char name[255];
62.1314 - cc_.reportError(node->pos(), Message_InvalidFieldExpression,
62.1315 - GetTypeName(hir->type(), name, sizeof(name)));
62.1316 -}
62.1317 -
62.1318 -static inline TokenKind
62.1319 -ToCompare(Expression *expr)
62.1320 -{
62.1321 - if (expr->isBinaryExpression()) {
62.1322 - BinaryExpression *b = expr->toBinaryExpression();
62.1323 - if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
62.1324 - return b->token();
62.1325 - } else if (expr->isUnaryExpression()) {
62.1326 - UnaryExpression *u = expr->toUnaryExpression();
62.1327 - if (u->token() == TOK_NOT)
62.1328 - return TOK_NOT;
62.1329 - }
62.1330 - return TOK_EOF;
62.1331 -}
62.1332 -
62.1333 -void
62.1334 -SemanticAnalysis::visitForTest(Expression *expr,
62.1335 - Label *trueBranch,
62.1336 - Label *falseBranch,
62.1337 - Label *fallthrough)
62.1338 -{
62.1339 - Local<Type> boolType(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
62.1340 -
62.1341 - TokenKind token = ToCompare(expr);
62.1342 - if (token == TOK_EOF || token == TOK_NOT) {
62.1343 - HIR *hir;
62.1344 - if (token == TOK_EOF)
62.1345 - hir = eval(expr);
62.1346 - else
62.1347 - hir = eval(expr->toUnaryExpression()->expression());
62.1348 - if (!hir)
62.1349 - return;
62.1350 - if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
62.1351 - return;
62.1352 -
62.1353 - discharge(hir);
62.1354 -
62.1355 - bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
62.1356 - Opcode op = jumpOnTrue ? OP_JT : OP_JF;
62.1357 -
62.1358 - if (fallthrough == falseBranch)
62.1359 - __ j(op, trueBranch);
62.1360 - else
62.1361 - __ j(op, falseBranch);
62.1362 - return;
62.1363 - }
62.1364 -
62.1365 - BinaryExpression *bin = expr->toBinaryExpression();
62.1366 - if (token == TOK_AND || token == TOK_OR) {
62.1367 - Label next;
62.1368 - if (token == TOK_AND)
62.1369 - visitForTest(bin->left(), &next, falseBranch, &next);
62.1370 - else
62.1371 - visitForTest(bin->left(), trueBranch, &next, &next);
62.1372 - __ bind(&next);
62.1373 - visitForTest(bin->right(), trueBranch, falseBranch, fallthrough);
62.1374 - return;
62.1375 - }
62.1376 -
62.1377 - HIR *left = eval(bin->left());
62.1378 - HIR *right = eval(bin->right());
62.1379 - if (!left || !right)
62.1380 - return;
62.1381 -
62.1382 - HIR *hir = binary(bin, bin->token(), left, right);
62.1383 - if (!hir)
62.1384 - return;
62.1385 - if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
62.1386 - return;
62.1387 -
62.1388 - discharge(hir);
62.1389 - if (fallthrough == trueBranch)
62.1390 - __ j(OP_JF, falseBranch);
62.1391 - else
62.1392 - __ j(OP_JT, trueBranch);
62.1393 -}
62.1394 -
62.1395 -HLValue *
62.1396 -SemanticAnalysis::lvalue(Expression *expr)
62.1397 -{
62.1398 - HIR *hir = eval(expr);
62.1399 - if (!hir)
62.1400 - return NULL;
62.1401 -
62.1402 - if (!hir->isLValue()) {
62.1403 - cc_.reportError(expr->pos(), Message_ExpectedLValue);
62.1404 - return NULL;
62.1405 - }
62.1406 -
62.1407 - return static_cast<HLValue *>(hir);
62.1408 -}
62.1409 -
62.1410 -HIR *
62.1411 -SemanticAnalysis::eval(Expression *expr)
62.1412 -{
62.1413 - assert(!hir_);
62.1414 - expr->accept(this);
62.1415 -
62.1416 - HIR *hir = hir_;
62.1417 - hir_ = NULL;
62.1418 -
62.1419 - return hir;
62.1420 -}
62.1421 -
62.1422 -void
62.1423 -SemanticAnalysis::discharge(HIR *hir)
62.1424 -{
62.1425 - EmitHIR(zone_, emitter_, hir);
62.1426 -}
62.1427 +/* vim: set ts=4 sw=4 tw=99 et:
62.1428 + *
62.1429 + * Copyright (C) 2012 David Anderson
62.1430 + *
62.1431 + * This file is part of SourcePawn.
62.1432 + *
62.1433 + * SourcePawn is free software: you can redistribute it and/or modify it under
62.1434 + * the terms of the GNU General Public License as published by the Free
62.1435 + * Software Foundation, either version 3 of the License, or (at your option)
62.1436 + * any later version.
62.1437 + *
62.1438 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
62.1439 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
62.1440 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
62.1441 + *
62.1442 + * You should have received a copy of the GNU General Public License along with
62.1443 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
62.1444 + */
62.1445 +#include <assert.h>
62.1446 +#include "../Zone.h"
62.1447 +#include "../Strings.h"
62.1448 +#include "../NativeTable.h"
62.1449 +#include "../TypeManager.h"
62.1450 +#include "../Modules.h"
62.1451 +#include "../Code.h"
62.1452 +#include "SemanticAnalysis.h"
62.1453 +#include "../Heap-inl.h"
62.1454 +
62.1455 +using namespace ke;
62.1456 +
62.1457 +#define __ emitter_.
62.1458 +
62.1459 +typedef BytecodeEmitter::Label Label;
62.1460 +
62.1461 +class AutoEnterScope
62.1462 +{
62.1463 + public:
62.1464 + AutoEnterScope(Scope **prevp, Scope *scope)
62.1465 + : prevp_(prevp),
62.1466 + prev_(*prevp),
62.1467 + scope_(scope)
62.1468 + {
62.1469 + if (!scope_)
62.1470 + return;
62.1471 + prev_ = *prevp_;
62.1472 + *prevp_ = scope;
62.1473 + assert(prev_ == scope->enclosing());
62.1474 + }
62.1475 + ~AutoEnterScope()
62.1476 + {
62.1477 + if (scope_)
62.1478 + *prevp_ = prev_;
62.1479 + }
62.1480 + private:
62.1481 + Scope **prevp_;
62.1482 + Scope *prev_;
62.1483 + Scope *scope_;
62.1484 +};
62.1485 +
62.1486 +SemanticAnalysis::SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit)
62.1487 + : zone_(zone),
62.1488 + pool_(zone->pool()),
62.1489 + cc_(cc),
62.1490 + unit_(unit),
62.1491 + hir_(NULL),
62.1492 + loop_(NULL)
62.1493 +{
62.1494 +}
62.1495 +
62.1496 +SemanticAnalysis::SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun)
62.1497 + : zone_(parent->zone_),
62.1498 + pool_(parent->pool_),
62.1499 + cc_(parent->cc_),
62.1500 + unit_(parent->unit_),
62.1501 + hir_(NULL),
62.1502 + scope_(parent->scope_),
62.1503 + fun_(fun),
62.1504 + loop_(NULL),
62.1505 + control_(NULL)
62.1506 +{
62.1507 +
62.1508 +}
62.1509 +
62.1510 +void
62.1511 +SemanticAnalysis::analyze()
62.1512 +{
62.1513 + scope_ = unit_->globalScope();
62.1514 +
62.1515 + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) {
62.1516 + Statement *stmt = unit_->tree()->statements()->at(i);
62.1517 + stmt->accept(this);
62.1518 + }
62.1519 +
62.1520 + Local<Code> code(zone_, __ finish());
62.1521 + if (!code)
62.1522 + return;
62.1523 + code->setModule(unit_->module());
62.1524 + unit_->module()->setCode(code);
62.1525 +
62.1526 +#ifndef NDEBUG
62.1527 +// Disassemble(code, stdout);
62.1528 +#endif
62.1529 +}
62.1530 +
62.1531 +void
62.1532 +SemanticAnalysis::visitFunctionStatement(FunctionStatement *stmt)
62.1533 +{
62.1534 + FunctionSymbol *sym = stmt->sym();
62.1535 + Local<FunctionType> type(zone_, sym->type());
62.1536 +
62.1537 + assert(scope_->kind() == Scope::GLOBAL);
62.1538 +
62.1539 + if (stmt->token() == TOK_NATIVE) {
62.1540 + // Define the native now.
62.1541 + size_t index;
62.1542 + if (!zone_->nativeTable()->add(stmt->name(), &index))
62.1543 + return;
62.1544 +
62.1545 + Local<Native> native(zone_, Native::New(zone_, type, index));
62.1546 + if (!native)
62.1547 + return;
62.1548 +
62.1549 + __ object(native);
62.1550 + __ setglobal(sym);
62.1551 + __ pop();
62.1552 + }
62.1553 +
62.1554 + // If the function is a forward or native, we don't have to do anything.
62.1555 + if (stmt->token() == TOK_NATIVE || stmt->token() == TOK_FORWARD)
62.1556 + return;
62.1557 +
62.1558 + SemanticAnalysis child(this, type);
62.1559 + Local<Function> funobj(zone_, child.compile(stmt));
62.1560 + if (!funobj)
62.1561 + return;
62.1562 +
62.1563 + __ object(funobj);
62.1564 + __ setglobal(sym);
62.1565 + if (stmt->token() == TOK_PUBLIC)
62.1566 + __ public_();
62.1567 + else
62.1568 + __ pop();
62.1569 +}
62.1570 +
62.1571 +Function *
62.1572 +SemanticAnalysis::compile(FunctionStatement *stmt)
62.1573 +{
62.1574 + __ setFirstLine(stmt->pos().line);
62.1575 +
62.1576 + AutoEnterScope argScope(&scope_, stmt->argScope());
62.1577 +
62.1578 + for (size_t i = 0; i < stmt->signature().parameters()->length(); i++) {
62.1579 + Parameter *param = stmt->signature().parameters()->at(i);
62.1580 + param->sym()->allocate(VariableSymbol::Arg, i);
62.1581 + }
62.1582 +
62.1583 + AutoEnterScope varScope(&scope_, stmt->varScope());
62.1584 + ControlStatus status = visitForControl(stmt->body());
62.1585 +
62.1586 + if (!fun_->returnType()->isVoid()) {
62.1587 + // If the function is not void, report if not all paths return a value.
62.1588 + // All other incorrect return cases have been caught already.
62.1589 + if (status.returns() == Returns_Sometimes) {
62.1590 + cc_.reportError(stmt->pos(), Message_NotAllPathsReturnValue);
62.1591 + return NULL;
62.1592 + }
62.1593 +
62.1594 + if (status.returns() == Returns_Never) {
62.1595 + cc_.reportError(stmt->pos(), Message_MissingReturnValue);
62.1596 + return NULL;
62.1597 + }
62.1598 + }
62.1599 +
62.1600 + Local<Code> code(zone_, __ finish());
62.1601 + if (!code)
62.1602 + return NULL;
62.1603 + code->setModule(unit_->module());
62.1604 +
62.1605 + Local<Function> fun(zone_, Function::New(zone_, code, fun_, stmt->name(), stmt->pos()));
62.1606 + if (!fun)
62.1607 + return NULL;
62.1608 +
62.1609 +#ifndef NDEBUG
62.1610 +// Disassemble(code, stdout);
62.1611 +#endif
62.1612 +
62.1613 + return fun;
62.1614 +}
62.1615 +
62.1616 +void
62.1617 +SemanticAnalysis::visitBlockStatement(BlockStatement *node)
62.1618 +{
62.1619 + AutoEnterScope scope(&scope_, node->scope());
62.1620 +
62.1621 + for (size_t i = 0; i < node->statements()->length(); i++) {
62.1622 + Statement *stmt = node->statements()->at(i);
62.1623 + __ note_position(stmt->pos());
62.1624 + stmt->accept(this);
62.1625 + assert(__ stackDepth() == 0);
62.1626 + }
62.1627 +}
62.1628 +
62.1629 +void
62.1630 +SemanticAnalysis::visitEnumStatement(EnumStatement *node)
62.1631 +{
62.1632 +}
62.1633 +
62.1634 +void
62.1635 +SemanticAnalysis::visitExpressionStatement(ExpressionStatement *node)
62.1636 +{
62.1637 + // While building HIR, we enter new pool and root scopes, since HIR
62.1638 + // creation is purely temporary.
62.1639 + PoolScope poolScope(zone_->pool());
62.1640 + RootScope rootScope(zone_);
62.1641 +
62.1642 + HIR *hir = eval(node->expression());
62.1643 + if (!hir)
62.1644 + return;
62.1645 +
62.1646 + discharge(hir);
62.1647 + if (!hir->type()->isVoid())
62.1648 + __ pop();
62.1649 +}
62.1650 +
62.1651 +void
62.1652 +SemanticAnalysis::ControlScope::merge(const ControlStatus &left, const ControlStatus &right)
62.1653 +{
62.1654 + // If both sides terminate in a return, we consider this a return as well.
62.1655 + if (left.returns() == Returns_Always && right.returns() == Returns_Always) {
62.1656 + terminate(Returns_Always);
62.1657 + return;
62.1658 + }
62.1659 +
62.1660 + ReturnStatus status = (left.returns() == Returns_Never && right.returns() == Returns_Never)
62.1661 + ? Returns_Never
62.1662 + : Returns_Sometimes;
62.1663 +
62.1664 + if (left.terminates() && right.terminates())
62.1665 + terminate(status);
62.1666 + else
62.1667 + returns(status);
62.1668 +}
62.1669 +
62.1670 +SemanticAnalysis::ControlStatus
62.1671 +SemanticAnalysis::visitForControl(Statement *statement)
62.1672 +{
62.1673 + ControlScope scope(&control_);
62.1674 + statement->accept(this);
62.1675 + return scope.status();
62.1676 +}
62.1677 +
62.1678 +void
62.1679 +SemanticAnalysis::visitIfStatement(IfStatement *node)
62.1680 +{
62.1681 + Label join;
62.1682 +
62.1683 + ControlStatus trueBranch;
62.1684 + ControlStatus falseBranch(false, Returns_Never);
62.1685 +
62.1686 + if (!node->ifFalse()) {
62.1687 + Label success;
62.1688 +
62.1689 + visitForTest(node->condition(), &success, &join, &success);
62.1690 + __ bind(&success);
62.1691 + trueBranch = visitForControl(node->ifTrue());
62.1692 + } else {
62.1693 + Label success, next;
62.1694 +
62.1695 + visitForTest(node->condition(), &success, &next, &success);
62.1696 + __ bind(&success);
62.1697 + trueBranch = visitForControl(node->ifTrue());
62.1698 + __ jump(&join);
62.1699 + __ bind(&next);
62.1700 + falseBranch = visitForControl(node->ifFalse());
62.1701 + }
62.1702 +
62.1703 + __ bind(&join);
62.1704 +
62.1705 + control_->merge(trueBranch, falseBranch);
62.1706 +}
62.1707 +
62.1708 +void
62.1709 +SemanticAnalysis::requireLifoStack()
62.1710 +{
62.1711 + if (!loop_)
62.1712 + return;
62.1713 +
62.1714 + loop_->setUsesLifoStack();
62.1715 +}
62.1716 +
62.1717 +SemanticAnalysis::ControlStatus
62.1718 +SemanticAnalysis::visitLoopBody(Statement *stmt)
62.1719 +{
62.1720 + // We always mark off a loop body, so on each edge, we can balance the
62.1721 + // LIFO stack. Right now, we don't have the ability to budget the LIFO
62.1722 + // stack ahead of time. If we turn out to never need the LIFO stack, we
62.1723 + // mark it as unnecessary. (The interpreter can't really make use of this,
62.1724 + // but the JIT can).
62.1725 + //
62.1726 + // Note that balancing the LIFO stack isn't even necessary, so this
62.1727 + // feature may be removed. All this mechanism does is mitigate the
62.1728 + // possibility that a long-running loop will overflow the LIFO region
62.1729 + // and therefore start requiring nursery allocations.
62.1730 + int pos = __ enterloop();
62.1731 + ControlStatus status = visitForControl(stmt);
62.1732 + __ leaveloop();
62.1733 +
62.1734 + if (loop_->usesLifoStack())
62.1735 + __ setLoopUsesLifoStack(pos);
62.1736 +
62.1737 + return status;
62.1738 +}
62.1739 +
62.1740 +void
62.1741 +SemanticAnalysis::visitForStatement(ForStatement *node)
62.1742 +{
62.1743 + AutoEnterScope scope(&scope_, node->scope());
62.1744 + PoolScope poolScope(zone_->pool());
62.1745 + RootScope rootScope(zone_);
62.1746 +
62.1747 + Label join, update;
62.1748 + LoopScope loop(scope_, &join, &update, &loop_);
62.1749 +
62.1750 + if (node->initialization())
62.1751 + node->initialization()->accept(this);
62.1752 +
62.1753 + Label header, test;
62.1754 + if (node->condition())
62.1755 + __ jump(&test);
62.1756 +
62.1757 + __ bind(&header);
62.1758 + ControlStatus status = visitLoopBody(node->body());
62.1759 +
62.1760 + __ bind(&update);
62.1761 + if (node->update())
62.1762 + node->update()->accept(this);
62.1763 +
62.1764 + if (node->condition()) {
62.1765 + __ bind(&test);
62.1766 + visitForTest(node->condition(), &header, &join, &join);
62.1767 + } else {
62.1768 + __ jump(&header);
62.1769 + }
62.1770 +
62.1771 + __ bind(&join);
62.1772 +
62.1773 + // If there was a condition, we treat this like a while loop. Otherwise,
62.1774 + // the join point is only reachable if the loop contains a break. The
62.1775 + // termination status doesn't tell us anything yet.
62.1776 + if (node->condition() || loop.breaks())
62.1777 + control_->merge(status, ControlStatus(false, Returns_Never));
62.1778 + else
62.1779 + control_->terminate(status.returns());
62.1780 +
62.1781 + assert(__ stackDepth() == 0);
62.1782 +}
62.1783 +
62.1784 +void
62.1785 +SemanticAnalysis::visitWhileStatement(WhileStatement *node)
62.1786 +{
62.1787 + PoolScope poolScope(zone_->pool());
62.1788 + RootScope rootScope(zone_);
62.1789 +
62.1790 + Label header, join;
62.1791 +
62.1792 + __ bind(&header);
62.1793 +
62.1794 + ControlStatus status;
62.1795 +
62.1796 + LoopScope loop(scope_, &join, &header, &loop_);
62.1797 + if (node->token() == TOK_WHILE) {
62.1798 + Label body;
62.1799 + visitForTest(node->condition(), &body, &join, &body);
62.1800 + status = visitLoopBody(node->body());
62.1801 + __ jump(&header);
62.1802 + } else {
62.1803 + status = visitLoopBody(node->body());
62.1804 + visitForTest(node->condition(), &header, &join, &join);
62.1805 + }
62.1806 +
62.1807 + __ bind(&join);
62.1808 +
62.1809 + // Detect loops that will always have a fork in the contro-flow graph.
62.1810 + // This will be a |while| loop, or a |do-while| loop whose body does
62.1811 + // not terminate. For now, we treat these as an |if| regardless of the
62.1812 + // direction the branch can take. That means the control-flow is always
62.1813 + // conditional.
62.1814 + if (node->token() == TOK_WHILE || status.terminates() || loop.breaks()) {
62.1815 + control_->merge(status, ControlStatus(false, Returns_Never));
62.1816 + } else {
62.1817 + // At this point, we've got a do-while loop with a |return| or
62.1818 + // |continue|, meaning that the rest of the block is unreachable.
62.1819 + control_->terminate(status.returns());
62.1820 + }
62.1821 +
62.1822 + assert(__ stackDepth() == 0);
62.1823 +}
62.1824 +
62.1825 +static inline Heap::Tenure
62.1826 +InferTenure(Symbol *sym)
62.1827 +{
62.1828 + if (sym->scope()->kind() == Scope::GLOBAL)
62.1829 + return Heap::Tenure_Old;
62.1830 +
62.1831 + // SP2's array semantics allow any array kind to escape, so we must use
62.1832 + // the normal heap. (Hopefully escape analysis can ease this pain later).
62.1833 + if (sym->type()->isArray())
62.1834 + return Heap::Tenure_Default;
62.1835 +
62.1836 + return Heap::Tenure_Default;
62.1837 +}
62.1838 +
62.1839 +void
62.1840 +SemanticAnalysis::visitVariableDeclaration(VariableDeclaration *node)
62.1841 +{
62.1842 + PoolScope poolScope(zone_->pool());
62.1843 + RootScope rootScope(zone_);
62.1844 +
62.1845 + Local<Type> type(zone_, node->sym()->type());
62.1846 +
62.1847 + if (node->sym()->type()->isVoid()) {
62.1848 + cc_.reportError(node->type()->pos(), Message_CannotDeclareVoid);
62.1849 + return;
62.1850 + }
62.1851 +
62.1852 + if (node->initialization()) {
62.1853 + HIR *hir = NULL;
62.1854 +
62.1855 + if ((hir = eval(node->initialization())) == NULL)
62.1856 + return;
62.1857 + if ((hir = coerce(hir, type, Coerce_Decl)) == NULL)
62.1858 + return;
62.1859 +
62.1860 + discharge(hir);
62.1861 + } else {
62.1862 + if (type->isInt32() || type->isEnum() ||
62.1863 + type->isChar() || type->isBool())
62.1864 + {
62.1865 + __ int_(0);
62.1866 + } else if (type->isFloat()) {
62.1867 + __ float_(0);
62.1868 + } else if (type->isArray()) {
62.1869 + Local<ArrayType> atype(zone_, ArrayType::cast(type));
62.1870 + Local<ArrayMap> map(zone_, atype->newMap());
62.1871 + if (!map)
62.1872 + return;
62.1873 +
62.1874 + if (atype->isFixedLength()) {
62.1875 + __ newarray(OP_NEWFIXED, map, InferTenure(node->sym()));
62.1876 + } else if (node->dims()->at(0)) {
62.1877 + // This may not be true if we allow typedefing, so :TODO:
62.1878 + // figure out proper semantics.
62.1879 + assert(node->dims()->length() == atype->levels());
62.1880 +
62.1881 + Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.1882 + for (size_t i = 0; i < node->dims()->length(); i++) {
62.1883 + Expression *expr = node->dims()->at(i);
62.1884 + if (expr) {
62.1885 + HIR *hir = eval(expr);
62.1886 + if (!hir || ((hir = coerce(hir, i32, Coerce_Arg)) == NULL))
62.1887 + return;
62.1888 + discharge(hir);
62.1889 + } else {
62.1890 + __ int_(0);
62.1891 + }
62.1892 + }
62.1893 + __ newarray(OP_NEWSIZED, map, InferTenure(node->sym()));
62.1894 + } else {
62.1895 + __ newarray(OP_NEWEMPTY, map, InferTenure(node->sym()));
62.1896 + }
62.1897 + } else {
62.1898 + assert(false);
62.1899 + }
62.1900 + }
62.1901 +
62.1902 + if (node->sym()->scope()->kind() != Scope::GLOBAL) {
62.1903 + if (!__ allocate(node->sym()))
62.1904 + return;
62.1905 + }
62.1906 +
62.1907 + set(node->sym());
62.1908 + __ pop();
62.1909 +}
62.1910 +
62.1911 +void
62.1912 +SemanticAnalysis::visitReturnStatement(ReturnStatement *node)
62.1913 +{
62.1914 + control_->returns(Returns_Always);
62.1915 +
62.1916 + if (!node->expression()) {
62.1917 + if (!fun_->returnType()->isVoid()) {
62.1918 + cc_.reportError(node->pos(), Message_MissingReturnValue);
62.1919 + return;
62.1920 + }
62.1921 +
62.1922 + __ returnvoid();
62.1923 + return;
62.1924 + }
62.1925 +
62.1926 + if (fun_->returnType()->isVoid()) {
62.1927 + cc_.reportError(node->pos(), Message_UsedVoidReturn);
62.1928 + return;
62.1929 + }
62.1930 +
62.1931 + PoolScope poolScope(zone_->pool());
62.1932 + RootScope rootScope(zone_);
62.1933 +
62.1934 + HIR *hir = eval(node->expression());
62.1935 + if (!hir)
62.1936 + return;
62.1937 +
62.1938 + Local<Type> returnType(zone_, fun_->returnType());
62.1939 + if ((hir = coerce(hir, returnType, Coerce_Return)) == NULL)
62.1940 + return;
62.1941 +
62.1942 + discharge(hir);
62.1943 +
62.1944 + if (hir->type()->isVoid())
62.1945 + __ returnvoid();
62.1946 + else
62.1947 + __ return_();
62.1948 +}
62.1949 +
62.1950 +void
62.1951 +SemanticAnalysis::visitBinaryExpression(BinaryExpression *node)
62.1952 +{
62.1953 + HIR *left = eval(node->left());
62.1954 + HIR *right = eval(node->right());
62.1955 + if (!left || !right)
62.1956 + return;
62.1957 +
62.1958 + hir_ = binary(node, node->token(), left, right);
62.1959 +}
62.1960 +
62.1961 +bool
62.1962 +SemanticAnalysis::checkArgumentCount(Handle<FunctionType> type, unsigned actual)
62.1963 +{
62.1964 + if (type->parameters()->length() == actual)
62.1965 + return true;
62.1966 +
62.1967 + if (actual > type->parameters()->length()) {
62.1968 + if (!type->isNative() || !type->isNativeVariadic())
62.1969 + return false;
62.1970 + return true;
62.1971 + }
62.1972 +
62.1973 + if (!type->defaults())
62.1974 + return false;
62.1975 +
62.1976 + // Missing arguments. See if there's a default argument for each missing
62.1977 + // actual.
62.1978 + for (unsigned i = actual; i < type->parameters()->length(); i++) {
62.1979 + if (!type->defaults()->at(i))
62.1980 + return false;
62.1981 + }
62.1982 +
62.1983 + return true;
62.1984 +}
62.1985 +
62.1986 +static unsigned
62.1987 +BindImplicitName(Module *from, ImplicitSymbol *sym)
62.1988 +{
62.1989 + if (sym->bound())
62.1990 + return sym->fieldIndex();
62.1991 +
62.1992 + Module *module = Module::cast(from->getImportAt(sym->index()));
62.1993 + StructMap *map = module->globals()->map();
62.1994 +
62.1995 + unsigned fieldIndex;
62.1996 + Descriptor *desc = map->type()->lookupField(sym->name(), &fieldIndex);
62.1997 + assert(desc && desc->type() == sym->type());
62.1998 +
62.1999 + sym->bind(fieldIndex);
62.2000 + return fieldIndex;
62.2001 +}
62.2002 +
62.2003 +void
62.2004 +SemanticAnalysis::visitNameProxy(NameProxy *proxy)
62.2005 +{
62.2006 + Symbol *sym = proxy->sym();
62.2007 +
62.2008 + switch (sym->kind()) {
62.2009 + case Symbol::kImport:
62.2010 + {
62.2011 + ImportSymbol *import = sym->toImport();
62.2012 + hir_ = new (pool_) HImport(proxy, sym->type(), import->index());
62.2013 + break;
62.2014 + }
62.2015 +
62.2016 + case Symbol::kImplicit:
62.2017 + {
62.2018 + ImplicitSymbol *import = sym->toImplicit();
62.2019 + unsigned fieldIndex = BindImplicitName(unit_->module(), import);
62.2020 +
62.2021 + hir_ = new (pool_) HImport(proxy, zone_->types()->getImportable(), import->index());
62.2022 + hir_ = new (pool_) HField(proxy, hir_, sym->type(), fieldIndex);
62.2023 + break;
62.2024 + }
62.2025 +
62.2026 + case Symbol::kConstant:
62.2027 + {
62.2028 + ConstantSymbol *val = sym->toConstant();
62.2029 + hir_ = new (pool_) HInteger(proxy, sym->type(), val->value().toInt());
62.2030 + break;
62.2031 + }
62.2032 +
62.2033 + // This is kind of screwy. Symbol::kFunction is like a constant we can't
62.2034 + // evaluate yet. Maybe we should extract the GLOBAL case and say that
62.2035 + // kFunction is only used for global functions (and use const vars for
62.2036 + // local functions).
62.2037 + case Symbol::kFunction:
62.2038 + case Symbol::kVariable:
62.2039 + {
62.2040 + Scope *in = sym->scope();
62.2041 + switch (in->kind()) {
62.2042 + case Scope::GLOBAL:
62.2043 + hir_ = new (pool_) HGlobal(proxy, sym);
62.2044 + break;
62.2045 +
62.2046 + case Scope::FUNCTION:
62.2047 + {
62.2048 + VariableSymbol *var = sym->toVariable();
62.2049 + assert(var->storage() == VariableSymbol::Arg);
62.2050 + hir_ = new (pool_) HLocal(proxy, var);
62.2051 + break;
62.2052 + }
62.2053 +
62.2054 + default:
62.2055 + {
62.2056 + VariableSymbol *var = sym->toVariable();
62.2057 + assert(in->kind() == Scope::BLOCK);
62.2058 + assert(var->storage() == VariableSymbol::Local);
62.2059 + hir_ = new (pool_) HLocal(proxy, var);
62.2060 + break;
62.2061 + }
62.2062 + }
62.2063 + break;
62.2064 + }
62.2065 +
62.2066 + default:
62.2067 + // :TODO:
62.2068 + assert(false);
62.2069 + }
62.2070 +}
62.2071 +
62.2072 +void
62.2073 +SemanticAnalysis::visitBooleanLiteral(BooleanLiteral *node)
62.2074 +{
62.2075 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
62.2076 + hir_ = new (pool_) HBoolean(node, type, node->token() == TOK_TRUE);
62.2077 +}
62.2078 +
62.2079 +void
62.2080 +SemanticAnalysis::visitIntegerLiteral(IntegerLiteral *lit)
62.2081 +{
62.2082 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.2083 + hir_ = new (pool_) HInteger(lit, type, lit->value());
62.2084 +}
62.2085 +
62.2086 +void
62.2087 +SemanticAnalysis::visitFloatLiteral(FloatLiteral *node)
62.2088 +{
62.2089 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Float));
62.2090 + hir_ = new (pool_) HFloat(node, type, (float)node->value());
62.2091 +}
62.2092 +
62.2093 +void
62.2094 +SemanticAnalysis::visitStringLiteral(StringLiteral *node)
62.2095 +{
62.2096 + Type *type = zone_->types()->getString();
62.2097 + hir_ = new (pool_) HString(node, type, node->string());
62.2098 +}
62.2099 +
62.2100 +void
62.2101 +SemanticAnalysis::visitCallExpression(CallExpression *node)
62.2102 +{
62.2103 + HIR *callee = eval(node->callee());
62.2104 + if (!callee)
62.2105 + return;
62.2106 +
62.2107 + if (!callee->type()->isFunction()) {
62.2108 + cc_.reportError(node->pos(), Message_CalleeNotFunction);
62.2109 + return;
62.2110 + }
62.2111 +
62.2112 + Local<FunctionType> fun(zone_, FunctionType::cast(callee->type()));
62.2113 +
62.2114 + if (!checkArgumentCount(fun, node->arguments()->length())) {
62.2115 + cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
62.2116 + return;
62.2117 + }
62.2118 +
62.2119 + if (fun->isForward()) {
62.2120 + cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
62.2121 + return;
62.2122 + }
62.2123 +
62.2124 + HIRList *args = new (pool_) HIRList;
62.2125 + for (unsigned i = 0; i < node->arguments()->length(); i++) {
62.2126 + Expression *expression = node->arguments()->at(i);
62.2127 + HIR *arg = eval(expression);
62.2128 + if (!arg)
62.2129 + return;
62.2130 +
62.2131 + Handle<Type> given = arg->type();
62.2132 +
62.2133 + bool mustComputeReference;
62.2134 + if (i >= fun->parameters()->length()) {
62.2135 + // Special handling for natives. Arguments past the formal must
62.2136 + // always have references computed. However, arrays are already
62.2137 + // references for natives.
62.2138 + assert(fun->isNative() && fun->isNativeVariadic());
62.2139 + mustComputeReference = !given->isReference() &&
62.2140 + !given->isArray();
62.2141 + } else {
62.2142 + Local<Type> actual(zone_, fun->parameterAt(i));
62.2143 +
62.2144 + if (expression->isIndexExpression() && arg->isIndex()) {
62.2145 + // If the expression is the form x[y], and this produced a
62.2146 + // normal array indexing operation, then we apply some
62.2147 + // special rules.
62.2148 +
62.2149 + if (actual->isReference()) {
62.2150 + // Disabled, since this doesn't have easily definable or
62.2151 + // sensible semantics with SP2 arrays, but we don't want
62.2152 + // to silently break SP1 semantics.
62.2153 + cc_.reportError(expression->pos(), Message_CannotComputeIndexRef);
62.2154 + return;
62.2155 + }
62.2156 +
62.2157 + // As a special rule to account for SP1 semantics, we allow x[y]
62.2158 + // to automatically compute a sliced, read-only array view if
62.2159 + // the desired type is an array of one more dimension than x[y]
62.2160 + // would return.
62.2161 + //
62.2162 + // As an additional restriction, this is only allowed for
62.2163 + // one-level char arrays, to minimize potential issues until
62.2164 + // we determine whether more compatibility is needed.
62.2165 + //
62.2166 + // Internally, for sanity, the dependent array operation does
62.2167 + // not necessarily create a dependent array. For extensible
62.2168 + // arrays, we instead create a duplicate arrary of just the
62.2169 + // sliced portion, rather than deal with the complexity of the
62.2170 + // source array being resized.
62.2171 + //
62.2172 + // Note that we don't really know whether a dependent array
62.2173 + // will be dependent at compile-time, so the dependent type's
62.2174 + // just inherits from the source.
62.2175 + if (actual->isArray()) {
62.2176 + HIndex *index = arg->toIndex();
62.2177 + Local<ArrayType> basetype(zone_, ArrayType::cast(index->base()->type()));
62.2178 + Local<ArrayType> atype(zone_, ArrayType::cast(actual));
62.2179 +
62.2180 + if (atype->isCharArray() && basetype->isCharArray()) {
62.2181 + // There is no possible way this will type check, so
62.2182 + // it's safe to just try something completely
62.2183 + // different.
62.2184 + Local<Type> slicetype(zone_);
62.2185 + if (basetype->isFixedLength()) {
62.2186 + // If the base type is fixed length, we need to
62.2187 + // compute a new dynamic array type based on the
62.2188 + // fixed array's contents and qualifiers.
62.2189 + Local<Type> contained(zone_, basetype->contained());
62.2190 + slicetype = zone_->types()->newArray(contained, ArrayType::DYNAMIC_ARRAY_SIZE);
62.2191 + if (!slicetype)
62.2192 + return;
62.2193 + slicetype = zone_->types()->qualify(slicetype, basetype->quals());
62.2194 + if (!slicetype)
62.2195 + return;
62.2196 + } else {
62.2197 + slicetype = basetype;
62.2198 + }
62.2199 + arg = new (pool_) HNewDependentArray(expression, slicetype, index->base(), index->index());
62.2200 + given = arg->type();
62.2201 + }
62.2202 + }
62.2203 + }
62.2204 +
62.2205 + if (actual->isReference()) {
62.2206 + // If the actual is a reference, the coercion rules are much
62.2207 + // stricter; the contained types must be identical.
62.2208 + // :TODO: make this not an assert
62.2209 + assert(ReferenceType::cast(actual)->contained() == arg->type());
62.2210 + } else {
62.2211 + // When we start overloading, coercion will have to happen later.
62.2212 + arg = coerce(arg, actual, Coerce_Arg);
62.2213 + if (!arg)
62.2214 + return;
62.2215 + }
62.2216 +
62.2217 + mustComputeReference = actual->isReference() && !given->isReference();
62.2218 + }
62.2219 +
62.2220 + if (mustComputeReference) {
62.2221 + // Refs always use the LIFO stack if they can.
62.2222 + arg = new (pool_) HToRef(arg->node(), arg->type(), arg);
62.2223 + requireLifoStack();
62.2224 + }
62.2225 +
62.2226 + if (!args->append(arg))
62.2227 + return;
62.2228 + }
62.2229 +
62.2230 + hir_ = new (pool_) HCall(node, fun->returnType(), callee, args);
62.2231 +}
62.2232 +
62.2233 +void
62.2234 +SemanticAnalysis::visitAssignment(Assignment *node)
62.2235 +{
62.2236 + HLValue *lval = lvalue(node->lvalue());
62.2237 + if (!lval)
62.2238 + return;
62.2239 +
62.2240 + if (lval->type()->quals() & TypeQual_Const) {
62.2241 + cc_.reportError(node->pos(), Message_CannotModifyConst);
62.2242 + return;
62.2243 + }
62.2244 +
62.2245 + HIR *hir = eval(node->expression());
62.2246 + if (!hir)
62.2247 + return;
62.2248 + if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
62.2249 + return;
62.2250 +
62.2251 + hir_ = new (pool_) HStore(node, node->token(), lval, hir);
62.2252 +}
62.2253 +
62.2254 +void
62.2255 +SemanticAnalysis::visitBreakStatement(BreakStatement *node)
62.2256 +{
62.2257 + if (!loop_) {
62.2258 + cc_.reportError(node->pos(), Message_BreakOutsideLoop);
62.2259 + return;
62.2260 + }
62.2261 +
62.2262 + loop_->setBreaks();
62.2263 + __ j(OP_BREAK, loop_->break_());
62.2264 +}
62.2265 +
62.2266 +void
62.2267 +SemanticAnalysis::visitContinueStatement(ContinueStatement *node)
62.2268 +{
62.2269 + if (!loop_) {
62.2270 + cc_.reportError(node->pos(), Message_ContinueOutsideLoop);
62.2271 + return;
62.2272 + }
62.2273 +
62.2274 + __ j(OP_CONTINUE, loop_->continue_());
62.2275 +}
62.2276 +
62.2277 +void
62.2278 +SemanticAnalysis::visitIndexExpression(IndexExpression *node)
62.2279 +{
62.2280 + HIR *left = eval(node->left());
62.2281 + if (!left)
62.2282 + return;
62.2283 +
62.2284 + HIR *right = eval(node->right());
62.2285 + if (!right)
62.2286 + return;
62.2287 +
62.2288 + // Hrm... yes, for now, let's coerce here.
62.2289 + Local<Type> i32(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.2290 + if ((right = coerce(right, i32, Coerce_Arg)) == NULL)
62.2291 + return;
62.2292 +
62.2293 + // Do not coerce here, there's no reason to yet.
62.2294 + if (!left->type()->isArray()) {
62.2295 + cc_.reportError(node->left()->pos(), Message_IndexBaseMustBeArray);
62.2296 + return;
62.2297 + }
62.2298 +
62.2299 + hir_ = new (pool_) HIndex(node,
62.2300 + ArrayType::cast(left->type())->contained(),
62.2301 + left,
62.2302 + right);
62.2303 +}
62.2304 +
62.2305 +void
62.2306 +SemanticAnalysis::visitIncDecExpression(IncDecExpression *node)
62.2307 +{
62.2308 + HLValue *lval = lvalue(node->expression());
62.2309 + if (!lval)
62.2310 + return;
62.2311 +
62.2312 + if (!lval->type()->isInt32() && !lval->type()->isFloat()) {
62.2313 + assert(false);
62.2314 + return;
62.2315 + }
62.2316 +
62.2317 + HIR *rval;
62.2318 + if (lval->type()->isInt32())
62.2319 + rval = new (pool_) HInteger(node, lval->type(), 1);
62.2320 + else
62.2321 + rval = new (pool_) HFloat(node, lval->type(), 1.0);
62.2322 +
62.2323 + if (node->postfix())
62.2324 + hir_ = new (pool_) HPostIncDec(node, node->token(), lval, rval);
62.2325 + else
62.2326 + hir_ = new (pool_) HStore(node, node->token(), lval, rval);
62.2327 +}
62.2328 +
62.2329 +Type *
62.2330 +SemanticAnalysis::coercionType(TokenKind token, HIR *left, HIR *right)
62.2331 +{
62.2332 + Local<Type> l(zone_, left->type());
62.2333 + Local<Type> r(zone_, right->type());
62.2334 +
62.2335 + if (l->isPod())
62.2336 + l = l->unqualified();
62.2337 + if (r->isPod())
62.2338 + r = r->unqualified();
62.2339 +
62.2340 + if ((token >= TOK_PLUS && token <= TOK_SLASH) ||
62.2341 + (token >= TOK_EQUALS && token <= TOK_GE))
62.2342 + {
62.2343 + // We allow: [float|int32] + [float|int32]
62.2344 + if (l->isFloat() && r->isInt32())
62.2345 + return l;
62.2346 + if (l->isInt32() && r->isFloat())
62.2347 + return r;
62.2348 + if (l->isInt32() && r->isInt32())
62.2349 + return l;
62.2350 +
62.2351 + if (l->isChar() && r->isInt32())
62.2352 + return r;
62.2353 + if (l->isInt32() && r->isChar())
62.2354 + return l;
62.2355 + }
62.2356 +
62.2357 + // :TODO: remove
62.2358 + assert(*l == *r);
62.2359 +
62.2360 + return left->type();
62.2361 +}
62.2362 +
62.2363 +HIR *
62.2364 +SemanticAnalysis::typeCheckArray(const SourcePosition &pos,
62.2365 + HIR *from,
62.2366 + Handle<ArrayType> argActual,
62.2367 + CoercionKind kind)
62.2368 +{
62.2369 + Local<Type> argGiven(zone_, from->type());
62.2370 +
62.2371 + // Special case: if we receive a string literal, and this is a char array,
62.2372 + // we allow a coercion.
62.2373 + if (from->isString() &&
62.2374 + argGiven->isString() &&
62.2375 + argActual->isArray() &&
62.2376 + ArrayType::cast(argActual)->isCharArray())
62.2377 + {
62.2378 + HString *hir = from->toString();
62.2379 + Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
62.2380 +
62.2381 + if (actual->isFixedLength()) {
62.2382 + if (hir->string()->length() + 1 > actual->fixedLength()) {
62.2383 + cc_.reportError(pos, Message_ArrayAssignmentTooBig);
62.2384 + return NULL;
62.2385 + }
62.2386 + }
62.2387 +
62.2388 + // Transform the string literal into an array literal. We give it the
62.2389 + // type of the left-hand side. The constness of the destination type
62.2390 + // will determine whether HArray duplicates it or not.
62.2391 + Local<ArrayMap> map(zone_, actual->newMap());
62.2392 + if (!map)
62.2393 + return NULL;
62.2394 +
62.2395 + Local<Array> array(zone_);
62.2396 + array = Array::NewString(zone_,
62.2397 + map,
62.2398 + hir->string()->chars(),
62.2399 + hir->string()->length(),
62.2400 + Heap::Tenure_Old);
62.2401 + if (!array)
62.2402 + return NULL;
62.2403 +
62.2404 + // Since we're creating a canonical copy of the char array, we have to
62.2405 + // be careful that it doesn't get mutated. There are two cases where
62.2406 + // we know it can't be mutated, and therefore don't need to specify
62.2407 + // that it be cloned after pushing it onto the stack.
62.2408 + //
62.2409 + // (1) The array type is const.
62.2410 + // (2) The array type is fixed-length, and the coercion is for
62.2411 + // assignment, meaning it will be immediately copied.
62.2412 + //
62.2413 + // We treat declaration separately from assignment, since for
62.2414 + // declaration we can just immediately use the cloned version.
62.2415 + bool shouldDuplicate = true;
62.2416 + if ((actual->quals() & TypeQual_Const) ||
62.2417 + (actual->isFixedLength() && kind == Coerce_Assign))
62.2418 + {
62.2419 + shouldDuplicate = false;
62.2420 + }
62.2421 +
62.2422 + return new (pool_) HArray(hir->node(), actual, array, shouldDuplicate);
62.2423 + }
62.2424 +
62.2425 + if (!argGiven->isArray()) {
62.2426 + cc_.reportError(pos, Message_ExpectedArray);
62.2427 + return NULL;
62.2428 + }
62.2429 +
62.2430 + Local<ArrayType> actual(zone_, ArrayType::cast(argActual));
62.2431 + Local<ArrayType> given(zone_, ArrayType::cast(argGiven));
62.2432 +
62.2433 + if (actual->levels() != given->levels()) {
62.2434 + cc_.reportError(pos, Message_ArrayDimensionsMismatch);
62.2435 + return NULL;
62.2436 + }
62.2437 +
62.2438 + unsigned level = 1;
62.2439 + while (true) {
62.2440 + if (actual->isFixedLength()) {
62.2441 + if (!given->isFixedLength()) {
62.2442 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
62.2443 + return NULL;
62.2444 + }
62.2445 +
62.2446 + if (actual->isCharArray()) {
62.2447 + // String assignment can have a truncated |given|.
62.2448 + if (given->fixedLength() > actual->fixedLength()) {
62.2449 + cc_.reportError(pos, Message_ArrayAssignmentTooBig);
62.2450 + return NULL;
62.2451 + }
62.2452 + } else {
62.2453 + if (given->fixedLength() != actual->fixedLength()) {
62.2454 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
62.2455 + return NULL;
62.2456 + }
62.2457 + }
62.2458 + } else if (given->isFixedLength()) {
62.2459 + // We do not allow assignments in the form:
62.2460 + // [][] = [][Y]
62.2461 + //
62.2462 + // Otherwise, the following code could break the size guarantees
62.2463 + // of the right-hand side:
62.2464 + //
62.2465 + // new x[][5];
62.2466 + // new y[][];
62.2467 + // new z[3];
62.2468 + //
62.2469 + //
62.2470 + // y = x;
62.2471 + // y[0] = z;
62.2472 + //
62.2473 + // Now |x[0]| contains a 3-length array.
62.2474 + if (level > 1) {
62.2475 + cc_.reportError(pos, Message_ArrayDimensionSizeMismatch, level);
62.2476 + return NULL;
62.2477 + }
62.2478 + }
62.2479 +
62.2480 + if (!given->contained()->isArray() || !actual->contained()->isArray())
62.2481 + break;
62.2482 +
62.2483 + given = ArrayType::cast(given->contained());
62.2484 + actual = ArrayType::cast(actual->contained());
62.2485 + }
62.2486 +
62.2487 + bool givenConst = !!(given->contained()->quals() & TypeQual_Const);
62.2488 + bool actualConst = !!(actual->contained()->quals() & TypeQual_Const);
62.2489 +
62.2490 + // These arrays must contain the same innermost type.
62.2491 + if (given->contained()->unqualified() != actual->contained()->unqualified() ||
62.2492 + (givenConst && !actualConst))
62.2493 + {
62.2494 + char aname[255];
62.2495 + char gname[255];
62.2496 + cc_.reportError(pos, Message_TypeMismatch,
62.2497 + GetTypeName(argActual, aname, sizeof(aname)),
62.2498 + GetTypeName(argGiven, gname, sizeof(gname)));
62.2499 + return NULL;
62.2500 + }
62.2501 +
62.2502 + return from;
62.2503 +}
62.2504 +
62.2505 +HIR *
62.2506 +SemanticAnalysis::typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to)
62.2507 +{
62.2508 + char fname[255];
62.2509 + char tname[255];
62.2510 + cc_.reportError(pos, Message_InvalidCoercion,
62.2511 + GetTypeName(from, fname, sizeof(fname)),
62.2512 + GetTypeName(to, tname, sizeof(tname)));
62.2513 + return NULL;
62.2514 +}
62.2515 +
62.2516 +HIR *
62.2517 +SemanticAnalysis::coerce(HIR *hir, Handle<Type> to, CoercionKind kind)
62.2518 +{
62.2519 + Local<Type> from(zone_, hir->type());
62.2520 +
62.2521 + // If the source is *ever* an importable, we just fail.
62.2522 + if (from->isImportable())
62.2523 + return typeFailure(hir->node()->pos(), from, to);
62.2524 +
62.2525 + if (from->isInt32() && to->isFloat())
62.2526 + return new (pool_) HConvert(hir->node(), to, OP_CVT_I2F, hir);
62.2527 + if (from->isInt32() && to->isBool())
62.2528 + return new (pool_) HConvert(hir->node(), to, OP_CVT_I2B, hir);
62.2529 +
62.2530 + if (to->isEnum() && from->unqualified() != to->unqualified())
62.2531 + return typeFailure(hir->node()->pos(), from, to);
62.2532 +
62.2533 + if (to->isArray()) {
62.2534 + Local<ArrayType> atype(zone_, ArrayType::cast(to));
62.2535 + return typeCheckArray(hir->node()->pos(), hir, atype, kind);
62.2536 + }
62.2537 +
62.2538 + return hir;
62.2539 +}
62.2540 +
62.2541 +void
62.2542 +SemanticAnalysis::set(VariableSymbol *sym)
62.2543 +{
62.2544 + if (sym->scope()->kind() == Scope::GLOBAL) {
62.2545 + __ setglobal(sym);
62.2546 + } else {
62.2547 + assert(sym->storage() == VariableSymbol::Local);
62.2548 + __ setlocal(sym);
62.2549 + }
62.2550 +}
62.2551 +
62.2552 +HIR *
62.2553 +SemanticAnalysis::binary(AstNode *node, TokenKind token, HIR *left, HIR *right)
62.2554 +{
62.2555 + Local<Type> coercion(zone_, coercionType(token, left, right));
62.2556 + if (!coercion)
62.2557 + return NULL;
62.2558 + if ((left = coerce(left, coercion, Coerce_Arg)) == NULL)
62.2559 + return NULL;
62.2560 + if ((right = coerce(right, coercion, Coerce_Arg)) == NULL)
62.2561 + return NULL;
62.2562 +
62.2563 + switch (token) {
62.2564 + case TOK_PLUS:
62.2565 + case TOK_MINUS:
62.2566 + case TOK_STAR:
62.2567 + case TOK_SLASH:
62.2568 + case TOK_PERCENT:
62.2569 + case TOK_AMPERSAND:
62.2570 + case TOK_BITOR:
62.2571 + case TOK_BITXOR:
62.2572 + case TOK_SHR:
62.2573 + case TOK_USHR:
62.2574 + case TOK_SHL:
62.2575 + return new (pool_) HBinary(node, left->type(), token, left, right);
62.2576 +
62.2577 + case TOK_EQUALS:
62.2578 + case TOK_NOTEQUALS:
62.2579 + case TOK_LT:
62.2580 + case TOK_LE:
62.2581 + case TOK_GT:
62.2582 + case TOK_GE:
62.2583 + case TOK_AND:
62.2584 + case TOK_OR:
62.2585 + {
62.2586 + Local<Type> result(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
62.2587 + return new (pool_) HBinary(node, result, token, left, right);
62.2588 + }
62.2589 +
62.2590 + default:
62.2591 + assert(false);
62.2592 + return NULL;
62.2593 + }
62.2594 +}
62.2595 +
62.2596 +static inline bool
62.2597 +IsValidUncheckedType(Type *type)
62.2598 +{
62.2599 + return type->isEnum() ||
62.2600 + type->isFloat() ||
62.2601 + type->isInt32() ||
62.2602 + type->isChar() ||
62.2603 + type->isUnchecked() ||
62.2604 + type->isBool();
62.2605 +}
62.2606 +
62.2607 +void
62.2608 +SemanticAnalysis::visitUnaryExpression(UnaryExpression *node)
62.2609 +{
62.2610 + HIR *hir = eval(node->expression());
62.2611 + if (!hir)
62.2612 + return;
62.2613 +
62.2614 + switch (node->token()) {
62.2615 + case TOK_TILDE:
62.2616 + {
62.2617 + if (!hir->type()->isInt32() && !hir->type()->isEnum()) {
62.2618 + char name[255];
62.2619 + cc_.reportError(node->pos(), Message_InvalidUnaryType,
62.2620 + "~",
62.2621 + GetTypeName(hir->type(), name, sizeof(name)));
62.2622 + }
62.2623 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.2624 + hir_ = new (pool_) HUnary(node, hir->type(), TOK_TILDE, hir);
62.2625 + return;
62.2626 + }
62.2627 +
62.2628 + case TOK_MINUS:
62.2629 + {
62.2630 + if (hir->type()->isInt32() || hir->type()->isEnum()) {
62.2631 + Local<Type> type(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
62.2632 + hir_ = new (pool_) HUnary(node, type, TOK_MINUS, hir);
62.2633 + return;
62.2634 + }
62.2635 + if (hir->type()->isFloat()) {
62.2636 + hir_ = new (pool_) HUnary(node, hir->type(), TOK_MINUS, hir);
62.2637 + return;
62.2638 + }
62.2639 +
62.2640 + char name[255];
62.2641 + cc_.reportError(node->pos(), Message_InvalidUnaryType,
62.2642 + "-",
62.2643 + GetTypeName(hir->type(), name, sizeof(name)));
62.2644 + break;
62.2645 + }
62.2646 +
62.2647 + default:
62.2648 + {
62.2649 + assert(node->token() == TOK_LABEL);
62.2650 +
62.2651 + TypeSymbol *sym = node->tag()->sym()->asType();
62.2652 + if (!sym) {
62.2653 + cc_.reportError(node->pos(), Message_IdentifierIsNotAType,
62.2654 + sym->name()->chars());
62.2655 + return;
62.2656 + }
62.2657 +
62.2658 + if (!IsValidUncheckedType(sym->effective())) {
62.2659 + char name[255];
62.2660 + cc_.reportError(node->pos(), Message_InvalidUncheckedCastTo,
62.2661 + GetTypeName(sym->type(), name, sizeof(name)));
62.2662 + return;
62.2663 + }
62.2664 + if (!IsValidUncheckedType(hir->type())) {
62.2665 + char name[255];
62.2666 + cc_.reportError(node->pos(), Message_InvalidUncheckedCastFrom,
62.2667 + GetTypeName(hir->type(), name, sizeof(name)));
62.2668 + return;
62.2669 + }
62.2670 +
62.2671 + hir_ = new (pool_) HUnary(node, sym->effective(), TOK_LABEL, hir);
62.2672 + break;
62.2673 + }
62.2674 + }
62.2675 +}
62.2676 +
62.2677 +void
62.2678 +SemanticAnalysis::import(HIR *hir, FieldExpression *node)
62.2679 +{
62.2680 + // Note that we don't care if the hir type is "importable", since we
62.2681 + // can only do anything if the important has a constant binding.
62.2682 + unsigned index = hir->toImport()->index();
62.2683 + Local<Importable> importable(zone_, unit_->module()->getImportAt(index));
62.2684 +
62.2685 + if (importable->isPackage()) {
62.2686 + // Look at what's already loaded and see if anything exists. We
62.2687 + // can't create stuff on-demand here since it's too late to add
62.2688 + // new translation units to the CompileContext.
62.2689 + Local<Package> package(zone_, Package::cast(importable));
62.2690 + Local<Importable> found(zone_, package->import(node->field()));
62.2691 + if (!found) {
62.2692 + cc_.reportError(node->pos(), Message_PackageDoesNotHaveMember, node->field()->chars());
62.2693 + return;
62.2694 + }
62.2695 +
62.2696 + // If we did find something, make sure it is in our import list.
62.2697 + // If we didn't explicitly import it, we have no right to use it.
62.2698 + for (index = 0; index < unit_->module()->imports(); index++) {
62.2699 + if (unit_->module()->getImportAt(index) == importable)
62.2700 + break;
62.2701 + }
62.2702 +
62.2703 + if (index == unit_->module()->imports()) {
62.2704 + cc_.reportError(node->pos(), Message_ImportWasNeverImported, node->field()->chars());
62.2705 + return;
62.2706 + }
62.2707 +
62.2708 + // Just create a new HImport.
62.2709 + hir_ = new (pool_) HImport(node, hir->type(), index);
62.2710 + } else {
62.2711 + // Modules can never have sub-modules or sub-packages.
62.2712 + unsigned index;
62.2713 + Local<Module> module(zone_, Module::cast(importable));
62.2714 + Local<StructMap> map(zone_, module->globals()->map());
62.2715 + Local<Descriptor> desc(zone_, map->type()->lookupField(node->field(), &index));
62.2716 + if (!desc) {
62.2717 + cc_.reportError(node->pos(), Message_FieldNotFound, node->field()->chars());
62.2718 + return;
62.2719 + }
62.2720 + hir_ = new (pool_) HField(node, hir, desc->type(), index);
62.2721 + }
62.2722 +}
62.2723 +
62.2724 +void
62.2725 +SemanticAnalysis::visitFieldExpression(FieldExpression *node)
62.2726 +{
62.2727 + HIR *hir = eval(node->left());
62.2728 + if (!hir)
62.2729 + return;
62.2730 +
62.2731 + if (hir->isImport()) {
62.2732 + import(hir, node);
62.2733 + return;
62.2734 + }
62.2735 +
62.2736 + char name[255];
62.2737 + cc_.reportError(node->pos(), Message_InvalidFieldExpression,
62.2738 + GetTypeName(hir->type(), name, sizeof(name)));
62.2739 +}
62.2740 +
62.2741 +static inline TokenKind
62.2742 +ToCompare(Expression *expr)
62.2743 +{
62.2744 + if (expr->isBinaryExpression()) {
62.2745 + BinaryExpression *b = expr->toBinaryExpression();
62.2746 + if (b->token() >= TOK_EQUALS && b->token() <= TOK_OR)
62.2747 + return b->token();
62.2748 + } else if (expr->isUnaryExpression()) {
62.2749 + UnaryExpression *u = expr->toUnaryExpression();
62.2750 + if (u->token() == TOK_NOT)
62.2751 + return TOK_NOT;
62.2752 + }
62.2753 + return TOK_EOF;
62.2754 +}
62.2755 +
62.2756 +void
62.2757 +SemanticAnalysis::visitForTest(Expression *expr,
62.2758 + Label *trueBranch,
62.2759 + Label *falseBranch,
62.2760 + Label *fallthrough)
62.2761 +{
62.2762 + Local<Type> boolType(zone_, zone_->types()->getPrimitive(PrimitiveType_Bool));
62.2763 +
62.2764 + TokenKind token = ToCompare(expr);
62.2765 + if (token == TOK_EOF || token == TOK_NOT) {
62.2766 + HIR *hir;
62.2767 + if (token == TOK_EOF)
62.2768 + hir = eval(expr);
62.2769 + else
62.2770 + hir = eval(expr->toUnaryExpression()->expression());
62.2771 + if (!hir)
62.2772 + return;
62.2773 + if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
62.2774 + return;
62.2775 +
62.2776 + discharge(hir);
62.2777 +
62.2778 + bool jumpOnTrue = (fallthrough == falseBranch) ^ (token == TOK_NOT);
62.2779 + Opcode op = jumpOnTrue ? OP_JT : OP_JF;
62.2780 +
62.2781 + if (fallthrough == falseBranch)
62.2782 + __ j(op, trueBranch);
62.2783 + else
62.2784 + __ j(op, falseBranch);
62.2785 + return;
62.2786 + }
62.2787 +
62.2788 + BinaryExpression *bin = expr->toBinaryExpression();
62.2789 + if (token == TOK_AND || token == TOK_OR) {
62.2790 + Label next;
62.2791 + if (token == TOK_AND)
62.2792 + visitForTest(bin->left(), &next, falseBranch, &next);
62.2793 + else
62.2794 + visitForTest(bin->left(), trueBranch, &next, &next);
62.2795 + __ bind(&next);
62.2796 + visitForTest(bin->right(), trueBranch, falseBranch, fallthrough);
62.2797 + return;
62.2798 + }
62.2799 +
62.2800 + HIR *left = eval(bin->left());
62.2801 + HIR *right = eval(bin->right());
62.2802 + if (!left || !right)
62.2803 + return;
62.2804 +
62.2805 + HIR *hir = binary(bin, bin->token(), left, right);
62.2806 + if (!hir)
62.2807 + return;
62.2808 + if ((hir = coerce(hir, boolType, Coerce_Arg)) == NULL)
62.2809 + return;
62.2810 +
62.2811 + discharge(hir);
62.2812 + if (fallthrough == trueBranch)
62.2813 + __ j(OP_JF, falseBranch);
62.2814 + else
62.2815 + __ j(OP_JT, trueBranch);
62.2816 +}
62.2817 +
62.2818 +HLValue *
62.2819 +SemanticAnalysis::lvalue(Expression *expr)
62.2820 +{
62.2821 + HIR *hir = eval(expr);
62.2822 + if (!hir)
62.2823 + return NULL;
62.2824 +
62.2825 + if (!hir->isLValue()) {
62.2826 + cc_.reportError(expr->pos(), Message_ExpectedLValue);
62.2827 + return NULL;
62.2828 + }
62.2829 +
62.2830 + return static_cast<HLValue *>(hir);
62.2831 +}
62.2832 +
62.2833 +HIR *
62.2834 +SemanticAnalysis::eval(Expression *expr)
62.2835 +{
62.2836 + assert(!hir_);
62.2837 + expr->accept(this);
62.2838 +
62.2839 + HIR *hir = hir_;
62.2840 + hir_ = NULL;
62.2841 +
62.2842 + return hir;
62.2843 +}
62.2844 +
62.2845 +void
62.2846 +SemanticAnalysis::discharge(HIR *hir)
62.2847 +{
62.2848 + EmitHIR(zone_, emitter_, hir);
62.2849 +}
63.1 --- a/src/compiler/SemanticAnalysis.h Mon Jun 10 00:46:29 2013 +0100
63.2 +++ b/src/compiler/SemanticAnalysis.h Mon Jun 10 01:04:43 2013 +0100
63.3 @@ -1,259 +1,259 @@
63.4 -/*
63.5 - * Copyright (C) 2012 David Anderson
63.6 - *
63.7 - * This file is part of SourcePawn.
63.8 - *
63.9 - * SourcePawn is free software: you can redistribute it and/or modify it under
63.10 - * the terms of the GNU General Public License as published by the Free
63.11 - * Software Foundation, either version 3 of the License, or (at your option)
63.12 - * any later version.
63.13 - *
63.14 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
63.15 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
63.16 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
63.17 - *
63.18 - * You should have received a copy of the GNU General Public License along with
63.19 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
63.20 - */
63.21 -#ifndef _include_sp2_sema_h_
63.22 -#define _include_sp2_sema_h_
63.23 -
63.24 -#include "AST.h"
63.25 -#include "HIR.h"
63.26 -#include "Scopes.h"
63.27 -#include "BytecodeEmitter.h"
63.28 -
63.29 -namespace ke {
63.30 -
63.31 -// Semantic analysis occurs after all names and types have been bound. It
63.32 -// performs the important task of validating the semantics and type safety
63.33 -// of a parse tree.
63.34 -//
63.35 -// The semantic analysis phase also produces bytecode. This occurs on a
63.36 -// statement-by-statement basis. The result of analyzing an expression is a
63.37 -// tree of operations which is then flattened.
63.38 -class SemanticAnalysis : public AstVisitor
63.39 -{
63.40 - public:
63.41 - SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit);
63.42 -
63.43 - void analyze();
63.44 -
63.45 - private:
63.46 - SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun);
63.47 - Function *compile(FunctionStatement *stmt);
63.48 -
63.49 - public:
63.50 - void visitFunctionStatement(FunctionStatement *node);
63.51 - void visitBlockStatement(BlockStatement *node);
63.52 - void visitExpressionStatement(ExpressionStatement *node);
63.53 - void visitReturnStatement(ReturnStatement *node);
63.54 - void visitEnumStatement(EnumStatement *node);
63.55 -
63.56 - void visitCallExpression(CallExpression *node);
63.57 - void visitNameProxy(NameProxy *name);
63.58 - void visitIntegerLiteral(IntegerLiteral *node);
63.59 - void visitFloatLiteral(FloatLiteral *node);
63.60 - void visitVariableDeclaration(VariableDeclaration *node);
63.61 - void visitForStatement(ForStatement *node);
63.62 - void visitWhileStatement(WhileStatement *node);
63.63 - void visitAssignment(Assignment *node);
63.64 - void visitBinaryExpression(BinaryExpression *node);
63.65 - void visitBreakStatement(BreakStatement *node);
63.66 - void visitContinueStatement(ContinueStatement *node);
63.67 - void visitIfStatement(IfStatement *node);
63.68 - void visitIndexExpression(IndexExpression *node);
63.69 - void visitIncDecExpression(IncDecExpression *node);
63.70 - void visitStringLiteral(StringLiteral *node);
63.71 - void visitUnaryExpression(UnaryExpression *node);
63.72 - void visitBooleanLiteral(BooleanLiteral *node);
63.73 - void visitFieldExpression(FieldExpression *node);
63.74 -#if 0
63.75 - void visitFunctionTypeStatement(FunctionTypeStatement *node);
63.76 - void visitImportStatement(ImportStatement *node);
63.77 - void visitStructureStatement(StructureStatement *node);
63.78 - void visitSwitchStatement(SwitchStatement *node);
63.79 -
63.80 - void visitTernaryExpression(TernaryExpression *node);
63.81 - void visitArrayLiteral(ArrayLiteral *node);
63.82 -#endif
63.83 -
63.84 - private:
63.85 - bool checkArgumentCount(Handle<FunctionType> type, unsigned actual);
63.86 - void import(HIR *hir, FieldExpression *node);
63.87 -
63.88 - private:
63.89 - enum CoercionKind {
63.90 - Coerce_Arg,
63.91 - Coerce_Return,
63.92 - Coerce_Decl,
63.93 - Coerce_Assign
63.94 - };
63.95 -
63.96 - // For a given control flow path, whether it returns.
63.97 - enum ReturnStatus
63.98 - {
63.99 - Returns_Never,
63.100 - Returns_Sometimes,
63.101 - Returns_Always
63.102 - };
63.103 -
63.104 - // For a given control flow path, whether it terminates,
63.105 - // and if it terminates, whether it returns.
63.106 - class ControlStatus
63.107 - {
63.108 - bool terminates_;
63.109 - ReturnStatus returns_;
63.110 -
63.111 - public:
63.112 - ControlStatus()
63.113 - {
63.114 - }
63.115 - ControlStatus(bool terminates, ReturnStatus returns)
63.116 - : terminates_(terminates),
63.117 - returns_(returns)
63.118 - {
63.119 - }
63.120 -
63.121 - bool terminates() const {
63.122 - return terminates_;
63.123 - }
63.124 - ReturnStatus returns() const {
63.125 - return returns_;
63.126 - }
63.127 - };
63.128 -
63.129 - class ControlScope
63.130 - {
63.131 - ReturnStatus returns_;
63.132 - ControlScope **prevp_;
63.133 - ControlScope *prev_;
63.134 - bool terminates_;
63.135 -
63.136 - public:
63.137 - ControlScope(ControlScope **prevp)
63.138 - : returns_(Returns_Never),
63.139 - prevp_(prevp),
63.140 - prev_(*prevp),
63.141 - terminates_(false)
63.142 - {
63.143 - *prevp_ = this;
63.144 - }
63.145 - ~ControlScope() {
63.146 - *prevp_ = prev_;
63.147 - }
63.148 - ControlStatus status() {
63.149 - return ControlStatus(terminates_, returns_);
63.150 - }
63.151 -
63.152 - void returns(ReturnStatus status) {
63.153 - // We allow multiple terminates, but only the first one takes
63.154 - // effect. For example, |break; continue;| is legal, but the
63.155 - // continue is unreachable.
63.156 - if (terminates_)
63.157 - return;
63.158 - if (status > returns_)
63.159 - returns_ = status;
63.160 - }
63.161 - void terminate(ReturnStatus status) {
63.162 - if (terminates_)
63.163 - return;
63.164 - terminates_ = true;
63.165 - returns_ = status;
63.166 - }
63.167 - void merge(const ControlStatus &left, const ControlStatus &right);
63.168 - void inherit(const ControlStatus &other);
63.169 - };
63.170 -
63.171 -
63.172 - void requireLifoStack();
63.173 - ControlStatus visitForControl(Statement *statement);
63.174 - ControlStatus visitLoopBody(Statement *stmt);
63.175 - void visitForTest(Expression *expr,
63.176 - BytecodeEmitter::Label *trueBranch,
63.177 - BytecodeEmitter::Label *falseBranch,
63.178 - BytecodeEmitter::Label *fallthrough);
63.179 - void set(VariableSymbol *sym);
63.180 - HIR *eval(Expression *expr);
63.181 - HIR *binary(AstNode *node, TokenKind token, HIR *left, HIR *right);
63.182 - HIR *coerce(HIR *from, Handle<Type> to, CoercionKind kind);
63.183 - Type *coercionType(TokenKind token, HIR *left, HIR *right);
63.184 - HLValue *lvalue(Expression *expr);
63.185 - void discharge(HIR *hir);
63.186 - HIR *typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to);
63.187 -
63.188 - HIR *typeCheckArray(const SourcePosition &pos,
63.189 - HIR *from,
63.190 - Handle<ArrayType> argActual,
63.191 - CoercionKind kind);
63.192 -
63.193 - private:
63.194 - // Used to target break/catch statements.
63.195 - class LoopScope
63.196 - {
63.197 - Scope *scope_;
63.198 - BytecodeEmitter::Label *bk_;
63.199 - BytecodeEmitter::Label *ct_;
63.200 - LoopScope **prevp_;
63.201 - LoopScope *prev_;
63.202 - bool usesLifoStack_;
63.203 - bool breaks_;
63.204 -
63.205 - public:
63.206 - LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
63.207 - LoopScope **prevp)
63.208 - : scope_(scope),
63.209 - bk_(bk),
63.210 - ct_(ct),
63.211 - prevp_(prevp),
63.212 - prev_(*prevp),
63.213 - usesLifoStack_(false),
63.214 - breaks_(false)
63.215 - {
63.216 - *prevp_ = this;
63.217 - }
63.218 -
63.219 - ~LoopScope()
63.220 - {
63.221 - *prevp_ = prev_;
63.222 - }
63.223 -
63.224 - BytecodeEmitter::Label *break_() {
63.225 - return bk_;
63.226 - }
63.227 - BytecodeEmitter::Label *continue_() {
63.228 - return ct_;
63.229 - }
63.230 - Scope *scope() {
63.231 - return scope_;
63.232 - }
63.233 - void setUsesLifoStack() {
63.234 - usesLifoStack_ = true;
63.235 - }
63.236 - bool usesLifoStack() const {
63.237 - return usesLifoStack_;
63.238 - }
63.239 - void setBreaks() {
63.240 - breaks_ = true;
63.241 - }
63.242 - bool breaks() const {
63.243 - return breaks_;
63.244 - }
63.245 - };
63.246 -
63.247 - private:
63.248 - Zone *zone_;
63.249 - PoolAllocator &pool_;
63.250 - CompileContext &cc_;
63.251 - TranslationUnit *unit_;
63.252 - HIR *hir_;
63.253 - Scope *scope_;
63.254 - BytecodeEmitter emitter_;
63.255 - ScopedRoot<FunctionType> fun_;
63.256 - LoopScope *loop_;
63.257 - ControlScope *control_;
63.258 -};
63.259 -
63.260 -} // namespace ke
63.261 -
63.262 -#endif // _include_sp2_sema_h_
63.263 +/*
63.264 + * Copyright (C) 2012 David Anderson
63.265 + *
63.266 + * This file is part of SourcePawn.
63.267 + *
63.268 + * SourcePawn is free software: you can redistribute it and/or modify it under
63.269 + * the terms of the GNU General Public License as published by the Free
63.270 + * Software Foundation, either version 3 of the License, or (at your option)
63.271 + * any later version.
63.272 + *
63.273 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
63.274 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
63.275 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
63.276 + *
63.277 + * You should have received a copy of the GNU General Public License along with
63.278 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
63.279 + */
63.280 +#ifndef _include_sp2_sema_h_
63.281 +#define _include_sp2_sema_h_
63.282 +
63.283 +#include "AST.h"
63.284 +#include "HIR.h"
63.285 +#include "Scopes.h"
63.286 +#include "BytecodeEmitter.h"
63.287 +
63.288 +namespace ke {
63.289 +
63.290 +// Semantic analysis occurs after all names and types have been bound. It
63.291 +// performs the important task of validating the semantics and type safety
63.292 +// of a parse tree.
63.293 +//
63.294 +// The semantic analysis phase also produces bytecode. This occurs on a
63.295 +// statement-by-statement basis. The result of analyzing an expression is a
63.296 +// tree of operations which is then flattened.
63.297 +class SemanticAnalysis : public AstVisitor
63.298 +{
63.299 + public:
63.300 + SemanticAnalysis(Zone *zone, CompileContext &cc, TranslationUnit *unit);
63.301 +
63.302 + void analyze();
63.303 +
63.304 + private:
63.305 + SemanticAnalysis(SemanticAnalysis *parent, Handle<FunctionType> fun);
63.306 + Function *compile(FunctionStatement *stmt);
63.307 +
63.308 + public:
63.309 + void visitFunctionStatement(FunctionStatement *node);
63.310 + void visitBlockStatement(BlockStatement *node);
63.311 + void visitExpressionStatement(ExpressionStatement *node);
63.312 + void visitReturnStatement(ReturnStatement *node);
63.313 + void visitEnumStatement(EnumStatement *node);
63.314 +
63.315 + void visitCallExpression(CallExpression *node);
63.316 + void visitNameProxy(NameProxy *name);
63.317 + void visitIntegerLiteral(IntegerLiteral *node);
63.318 + void visitFloatLiteral(FloatLiteral *node);
63.319 + void visitVariableDeclaration(VariableDeclaration *node);
63.320 + void visitForStatement(ForStatement *node);
63.321 + void visitWhileStatement(WhileStatement *node);
63.322 + void visitAssignment(Assignment *node);
63.323 + void visitBinaryExpression(BinaryExpression *node);
63.324 + void visitBreakStatement(BreakStatement *node);
63.325 + void visitContinueStatement(ContinueStatement *node);
63.326 + void visitIfStatement(IfStatement *node);
63.327 + void visitIndexExpression(IndexExpression *node);
63.328 + void visitIncDecExpression(IncDecExpression *node);
63.329 + void visitStringLiteral(StringLiteral *node);
63.330 + void visitUnaryExpression(UnaryExpression *node);
63.331 + void visitBooleanLiteral(BooleanLiteral *node);
63.332 + void visitFieldExpression(FieldExpression *node);
63.333 +#if 0
63.334 + void visitFunctionTypeStatement(FunctionTypeStatement *node);
63.335 + void visitImportStatement(ImportStatement *node);
63.336 + void visitStructureStatement(StructureStatement *node);
63.337 + void visitSwitchStatement(SwitchStatement *node);
63.338 +
63.339 + void visitTernaryExpression(TernaryExpression *node);
63.340 + void visitArrayLiteral(ArrayLiteral *node);
63.341 +#endif
63.342 +
63.343 + private:
63.344 + bool checkArgumentCount(Handle<FunctionType> type, unsigned actual);
63.345 + void import(HIR *hir, FieldExpression *node);
63.346 +
63.347 + private:
63.348 + enum CoercionKind {
63.349 + Coerce_Arg,
63.350 + Coerce_Return,
63.351 + Coerce_Decl,
63.352 + Coerce_Assign
63.353 + };
63.354 +
63.355 + // For a given control flow path, whether it returns.
63.356 + enum ReturnStatus
63.357 + {
63.358 + Returns_Never,
63.359 + Returns_Sometimes,
63.360 + Returns_Always
63.361 + };
63.362 +
63.363 + // For a given control flow path, whether it terminates,
63.364 + // and if it terminates, whether it returns.
63.365 + class ControlStatus
63.366 + {
63.367 + bool terminates_;
63.368 + ReturnStatus returns_;
63.369 +
63.370 + public:
63.371 + ControlStatus()
63.372 + {
63.373 + }
63.374 + ControlStatus(bool terminates, ReturnStatus returns)
63.375 + : terminates_(terminates),
63.376 + returns_(returns)
63.377 + {
63.378 + }
63.379 +
63.380 + bool terminates() const {
63.381 + return terminates_;
63.382 + }
63.383 + ReturnStatus returns() const {
63.384 + return returns_;
63.385 + }
63.386 + };
63.387 +
63.388 + class ControlScope
63.389 + {
63.390 + ReturnStatus returns_;
63.391 + ControlScope **prevp_;
63.392 + ControlScope *prev_;
63.393 + bool terminates_;
63.394 +
63.395 + public:
63.396 + ControlScope(ControlScope **prevp)
63.397 + : returns_(Returns_Never),
63.398 + prevp_(prevp),
63.399 + prev_(*prevp),
63.400 + terminates_(false)
63.401 + {
63.402 + *prevp_ = this;
63.403 + }
63.404 + ~ControlScope() {
63.405 + *prevp_ = prev_;
63.406 + }
63.407 + ControlStatus status() {
63.408 + return ControlStatus(terminates_, returns_);
63.409 + }
63.410 +
63.411 + void returns(ReturnStatus status) {
63.412 + // We allow multiple terminates, but only the first one takes
63.413 + // effect. For example, |break; continue;| is legal, but the
63.414 + // continue is unreachable.
63.415 + if (terminates_)
63.416 + return;
63.417 + if (status > returns_)
63.418 + returns_ = status;
63.419 + }
63.420 + void terminate(ReturnStatus status) {
63.421 + if (terminates_)
63.422 + return;
63.423 + terminates_ = true;
63.424 + returns_ = status;
63.425 + }
63.426 + void merge(const ControlStatus &left, const ControlStatus &right);
63.427 + void inherit(const ControlStatus &other);
63.428 + };
63.429 +
63.430 +
63.431 + void requireLifoStack();
63.432 + ControlStatus visitForControl(Statement *statement);
63.433 + ControlStatus visitLoopBody(Statement *stmt);
63.434 + void visitForTest(Expression *expr,
63.435 + BytecodeEmitter::Label *trueBranch,
63.436 + BytecodeEmitter::Label *falseBranch,
63.437 + BytecodeEmitter::Label *fallthrough);
63.438 + void set(VariableSymbol *sym);
63.439 + HIR *eval(Expression *expr);
63.440 + HIR *binary(AstNode *node, TokenKind token, HIR *left, HIR *right);
63.441 + HIR *coerce(HIR *from, Handle<Type> to, CoercionKind kind);
63.442 + Type *coercionType(TokenKind token, HIR *left, HIR *right);
63.443 + HLValue *lvalue(Expression *expr);
63.444 + void discharge(HIR *hir);
63.445 + HIR *typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to);
63.446 +
63.447 + HIR *typeCheckArray(const SourcePosition &pos,
63.448 + HIR *from,
63.449 + Handle<ArrayType> argActual,
63.450 + CoercionKind kind);
63.451 +
63.452 + private:
63.453 + // Used to target break/catch statements.
63.454 + class LoopScope
63.455 + {
63.456 + Scope *scope_;
63.457 + BytecodeEmitter::Label *bk_;
63.458 + BytecodeEmitter::Label *ct_;
63.459 + LoopScope **prevp_;
63.460 + LoopScope *prev_;
63.461 + bool usesLifoStack_;
63.462 + bool breaks_;
63.463 +
63.464 + public:
63.465 + LoopScope(Scope *scope, BytecodeEmitter::Label *bk, BytecodeEmitter::Label *ct,
63.466 + LoopScope **prevp)
63.467 + : scope_(scope),
63.468 + bk_(bk),
63.469 + ct_(ct),
63.470 + prevp_(prevp),
63.471 + prev_(*prevp),
63.472 + usesLifoStack_(false),
63.473 + breaks_(false)
63.474 + {
63.475 + *prevp_ = this;
63.476 + }
63.477 +
63.478 + ~LoopScope()
63.479 + {
63.480 + *prevp_ = prev_;
63.481 + }
63.482 +
63.483 + BytecodeEmitter::Label *break_() {
63.484 + return bk_;
63.485 + }
63.486 + BytecodeEmitter::Label *continue_() {
63.487 + return ct_;
63.488 + }
63.489 + Scope *scope() {
63.490 + return scope_;
63.491 + }
63.492 + void setUsesLifoStack() {
63.493 + usesLifoStack_ = true;
63.494 + }
63.495 + bool usesLifoStack() const {
63.496 + return usesLifoStack_;
63.497 + }
63.498 + void setBreaks() {
63.499 + breaks_ = true;
63.500 + }
63.501 + bool breaks() const {
63.502 + return breaks_;
63.503 + }
63.504 + };
63.505 +
63.506 + private:
63.507 + Zone *zone_;
63.508 + PoolAllocator &pool_;
63.509 + CompileContext &cc_;
63.510 + TranslationUnit *unit_;
63.511 + HIR *hir_;
63.512 + Scope *scope_;
63.513 + BytecodeEmitter emitter_;
63.514 + ScopedRoot<FunctionType> fun_;
63.515 + LoopScope *loop_;
63.516 + ControlScope *control_;
63.517 +};
63.518 +
63.519 +} // namespace ke
63.520 +
63.521 +#endif // _include_sp2_sema_h_
64.1 --- a/src/compiler/Symbols.cpp Mon Jun 10 00:46:29 2013 +0100
64.2 +++ b/src/compiler/Symbols.cpp Mon Jun 10 01:04:43 2013 +0100
64.3 @@ -1,22 +1,22 @@
64.4 -/* vim: set ts=4 sw=4 tw=99 et:
64.5 - *
64.6 - * Copyright (C) 2012 David Anderson
64.7 - *
64.8 - * This file is part of JITCraft.
64.9 - *
64.10 - * JITCraft is free software: you can redistribute it and/or modify it under
64.11 - * the terms of the GNU General Public License as published by the Free
64.12 - * Software Foundation, either version 3 of the License, or (at your option)
64.13 - * any later version.
64.14 - *
64.15 - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
64.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
64.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
64.18 - *
64.19 - * You should have received a copy of the GNU General Public License along with
64.20 - * JITCraft. If not, see http://www.gnu.org/licenses/.
64.21 - */
64.22 -#include "Symbols.h"
64.23 -#include "../Heap-inl.h"
64.24 -#include "../Handles-inl.h"
64.25 -
64.26 +/* vim: set ts=4 sw=4 tw=99 et:
64.27 + *
64.28 + * Copyright (C) 2012 David Anderson
64.29 + *
64.30 + * This file is part of JITCraft.
64.31 + *
64.32 + * JITCraft is free software: you can redistribute it and/or modify it under
64.33 + * the terms of the GNU General Public License as published by the Free
64.34 + * Software Foundation, either version 3 of the License, or (at your option)
64.35 + * any later version.
64.36 + *
64.37 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
64.38 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
64.39 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
64.40 + *
64.41 + * You should have received a copy of the GNU General Public License along with
64.42 + * JITCraft. If not, see http://www.gnu.org/licenses/.
64.43 + */
64.44 +#include "Symbols.h"
64.45 +#include "../Heap-inl.h"
64.46 +#include "../Handles-inl.h"
64.47 +
65.1 --- a/src/compiler/Symbols.h Mon Jun 10 00:46:29 2013 +0100
65.2 +++ b/src/compiler/Symbols.h Mon Jun 10 01:04:43 2013 +0100
65.3 @@ -1,278 +1,278 @@
65.4 -/* vim: set ts=4 sw=4 tw=99 et:
65.5 - *
65.6 - * Copyright (C) 2012 David Anderson
65.7 - *
65.8 - * This file is part of SourcePawn.
65.9 - *
65.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
65.11 - * the terms of the GNU General Public License as published by the Free
65.12 - * Software Foundation, either version 3 of the License, or (at your option)
65.13 - * any later version.
65.14 - *
65.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
65.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
65.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
65.18 - *
65.19 - * You should have received a copy of the GNU General Public License along with
65.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
65.21 - */
65.22 -#ifndef _include_sp2_symbol_h_
65.23 -#define _include_sp2_symbol_h_
65.24 -
65.25 -#include "../PoolAllocator.h"
65.26 -#include "../Handles.h"
65.27 -#include "../Opcodes.h"
65.28 -#include "../Types.h"
65.29 -#include "../Strings.h"
65.30 -
65.31 -namespace ke {
65.32 -
65.33 -class String;
65.34 -
65.35 -#define SYMBOL_KINDS(_) \
65.36 - /* Any kind of variable or argument produces a VariableSymbol. */ \
65.37 - _(Variable) \
65.38 - /* A function declaration produces a FunctionSymbol. */ \
65.39 - _(Function) \
65.40 - /* A named constant produces a ConstantSymbol. */ \
65.41 - _(Constant) \
65.42 - /* A named type (class struct, typedef, etc) produces a TypeSymbol. */ \
65.43 - _(Type) \
65.44 - /* An import name. */ \
65.45 - _(Import) \
65.46 - /* A name implicitly derived from an import. */ \
65.47 - _(Implicit)
65.48 -
65.49 -#define _(name) class name##Symbol;
65.50 -SYMBOL_KINDS(_)
65.51 -#undef _
65.52 -
65.53 -class Scope;
65.54 -
65.55 -// A symbol represents the declaration of a named entity.
65.56 -class Symbol : public PoolObject
65.57 -{
65.58 - public:
65.59 - enum Kind {
65.60 -# define _(name) k##name,
65.61 - SYMBOL_KINDS(_)
65.62 -# undef _
65.63 - kTotalSymbolKinds
65.64 - };
65.65 -
65.66 - public:
65.67 - Symbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
65.68 - : scope_(scope),
65.69 - name_(name),
65.70 - pos_(pos)
65.71 - {
65.72 - }
65.73 -
65.74 - virtual Kind kind() const = 0;
65.75 -
65.76 - Handle<String> name() const {
65.77 - return name_;
65.78 - }
65.79 - const SourcePosition &pos() const {
65.80 - return pos_;
65.81 - }
65.82 - Handle<Type> type() const {
65.83 - return type_;
65.84 - }
65.85 - Scope *scope() const {
65.86 - return scope_;
65.87 - }
65.88 -
65.89 - public:
65.90 -#define _(name) \
65.91 - bool is##name() const { \
65.92 - return (kind() == k##name); \
65.93 - } \
65.94 - name##Symbol *as##name() { \
65.95 - if (is##name()) \
65.96 - return to##name(); \
65.97 - return NULL; \
65.98 - } \
65.99 - name##Symbol *to##name() { \
65.100 - assert(is##name()); \
65.101 - return reinterpret_cast<name##Symbol *>(this); \
65.102 - }
65.103 - SYMBOL_KINDS(_)
65.104 -#undef _
65.105 -
65.106 - private:
65.107 - Scope *scope_;
65.108 - ScopedRoot<String> name_;
65.109 - SourcePosition pos_;
65.110 -
65.111 - protected:
65.112 - ScopedRoot<Type> type_;
65.113 -};
65.114 -
65.115 -class VariableSymbol : public Symbol
65.116 -{
65.117 - public:
65.118 - enum Storage {
65.119 - Unknown,
65.120 - Local,
65.121 - Arg,
65.122 - Heap
65.123 - };
65.124 -
65.125 - public:
65.126 - VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
65.127 - : Symbol(scope, name, pos),
65.128 - storage_(Unknown)
65.129 - {
65.130 - }
65.131 -
65.132 - VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type)
65.133 - : Symbol(scope, name, pos),
65.134 - storage_(Unknown)
65.135 - {
65.136 - type_ = type;
65.137 - }
65.138 -
65.139 - Kind kind() const {
65.140 - return kVariable;
65.141 - }
65.142 - void setType(Type *type) {
65.143 - assert(!type_);
65.144 - type_ = type;
65.145 - }
65.146 - void allocate(Storage storage, unsigned slot) {
65.147 - storage_ = storage;
65.148 - slot_ = slot;
65.149 - }
65.150 - Storage storage() const {
65.151 - return storage_;
65.152 - }
65.153 - unsigned slot() const {
65.154 - assert(storage() != Unknown);
65.155 - return slot_;
65.156 - }
65.157 -
65.158 - private:
65.159 - Storage storage_;
65.160 - unsigned slot_;
65.161 -};
65.162 -
65.163 -class TypeSymbol : public Symbol
65.164 -{
65.165 - public:
65.166 - TypeSymbol(Scope *scope, Handle<String> name, Handle<Type> type, Handle<Type> effective)
65.167 - : Symbol(scope, name, SourcePosition()),
65.168 - effective_(effective)
65.169 - {
65.170 - type_ = type;
65.171 - }
65.172 -
65.173 - Kind kind() const {
65.174 - return kType;
65.175 - }
65.176 - Handle<Type> effective() {
65.177 - return effective_;
65.178 - }
65.179 -
65.180 - private:
65.181 - ScopedRoot<Type> effective_;
65.182 -};
65.183 -
65.184 -class FunctionSymbol : public Symbol
65.185 -{
65.186 - public:
65.187 - FunctionSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<FunctionType> type)
65.188 - : Symbol(scope, name, pos)
65.189 - {
65.190 - type_ = type;
65.191 - }
65.192 -
65.193 - Kind kind() const {
65.194 - return kFunction;
65.195 - }
65.196 - FunctionType *type() const {
65.197 - return FunctionType::cast(type_);
65.198 - }
65.199 -};
65.200 -
65.201 -class ConstantSymbol : public Symbol
65.202 -{
65.203 - public:
65.204 - ConstantSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
65.205 - const BoxedPrimitive &prim)
65.206 - : Symbol(scope, name, pos),
65.207 - value_(prim)
65.208 - {
65.209 - type_ = type;
65.210 - }
65.211 -
65.212 - Kind kind() const {
65.213 - return kConstant;
65.214 - }
65.215 - const BoxedPrimitive &value() const {
65.216 - return value_;
65.217 - }
65.218 -
65.219 - private:
65.220 - BoxedPrimitive value_;
65.221 -};
65.222 -
65.223 -class ImportSymbol : public Symbol
65.224 -{
65.225 - public:
65.226 - ImportSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
65.227 - unsigned index)
65.228 - : Symbol(scope, name, pos),
65.229 - index_(index)
65.230 - {
65.231 - type_ = type;
65.232 - }
65.233 -
65.234 - Kind kind() const {
65.235 - return kImport;
65.236 - }
65.237 - unsigned index() const {
65.238 - return index_;
65.239 - }
65.240 -
65.241 - private:
65.242 - unsigned index_;
65.243 -};
65.244 -
65.245 -class ImplicitSymbol : public Symbol
65.246 -{
65.247 - public:
65.248 - ImplicitSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
65.249 - unsigned index)
65.250 - : Symbol(scope, name, pos),
65.251 - index_(index),
65.252 - fieldIndex_(unsigned(-1))
65.253 - {
65.254 - type_ = type;
65.255 - }
65.256 -
65.257 - bool bound() const {
65.258 - return fieldIndex_ != unsigned(-1);
65.259 - }
65.260 - Kind kind() const {
65.261 - return kImplicit;
65.262 - }
65.263 - unsigned index() const {
65.264 - return index_;
65.265 - }
65.266 - void bind(unsigned fieldIndex) {
65.267 - fieldIndex_ = fieldIndex;
65.268 - }
65.269 - unsigned fieldIndex() const {
65.270 - assert(bound());
65.271 - return fieldIndex_;
65.272 - }
65.273 -
65.274 - private:
65.275 - unsigned index_;
65.276 - unsigned fieldIndex_;
65.277 -};
65.278 -
65.279 -}
65.280 -
65.281 -#endif // _include_sp2_symbol_h_
65.282 +/* vim: set ts=4 sw=4 tw=99 et:
65.283 + *
65.284 + * Copyright (C) 2012 David Anderson
65.285 + *
65.286 + * This file is part of SourcePawn.
65.287 + *
65.288 + * SourcePawn is free software: you can redistribute it and/or modify it under
65.289 + * the terms of the GNU General Public License as published by the Free
65.290 + * Software Foundation, either version 3 of the License, or (at your option)
65.291 + * any later version.
65.292 + *
65.293 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
65.294 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
65.295 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
65.296 + *
65.297 + * You should have received a copy of the GNU General Public License along with
65.298 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
65.299 + */
65.300 +#ifndef _include_sp2_symbol_h_
65.301 +#define _include_sp2_symbol_h_
65.302 +
65.303 +#include "../PoolAllocator.h"
65.304 +#include "../Handles.h"
65.305 +#include "../Opcodes.h"
65.306 +#include "../Types.h"
65.307 +#include "../Strings.h"
65.308 +
65.309 +namespace ke {
65.310 +
65.311 +class String;
65.312 +
65.313 +#define SYMBOL_KINDS(_) \
65.314 + /* Any kind of variable or argument produces a VariableSymbol. */ \
65.315 + _(Variable) \
65.316 + /* A function declaration produces a FunctionSymbol. */ \
65.317 + _(Function) \
65.318 + /* A named constant produces a ConstantSymbol. */ \
65.319 + _(Constant) \
65.320 + /* A named type (class struct, typedef, etc) produces a TypeSymbol. */ \
65.321 + _(Type) \
65.322 + /* An import name. */ \
65.323 + _(Import) \
65.324 + /* A name implicitly derived from an import. */ \
65.325 + _(Implicit)
65.326 +
65.327 +#define _(name) class name##Symbol;
65.328 +SYMBOL_KINDS(_)
65.329 +#undef _
65.330 +
65.331 +class Scope;
65.332 +
65.333 +// A symbol represents the declaration of a named entity.
65.334 +class Symbol : public PoolObject
65.335 +{
65.336 + public:
65.337 + enum Kind {
65.338 +# define _(name) k##name,
65.339 + SYMBOL_KINDS(_)
65.340 +# undef _
65.341 + kTotalSymbolKinds
65.342 + };
65.343 +
65.344 + public:
65.345 + Symbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
65.346 + : scope_(scope),
65.347 + name_(name),
65.348 + pos_(pos)
65.349 + {
65.350 + }
65.351 +
65.352 + virtual Kind kind() const = 0;
65.353 +
65.354 + Handle<String> name() const {
65.355 + return name_;
65.356 + }
65.357 + const SourcePosition &pos() const {
65.358 + return pos_;
65.359 + }
65.360 + Handle<Type> type() const {
65.361 + return type_;
65.362 + }
65.363 + Scope *scope() const {
65.364 + return scope_;
65.365 + }
65.366 +
65.367 + public:
65.368 +#define _(name) \
65.369 + bool is##name() const { \
65.370 + return (kind() == k##name); \
65.371 + } \
65.372 + name##Symbol *as##name() { \
65.373 + if (is##name()) \
65.374 + return to##name(); \
65.375 + return NULL; \
65.376 + } \
65.377 + name##Symbol *to##name() { \
65.378 + assert(is##name()); \
65.379 + return reinterpret_cast<name##Symbol *>(this); \
65.380 + }
65.381 + SYMBOL_KINDS(_)
65.382 +#undef _
65.383 +
65.384 + private:
65.385 + Scope *scope_;
65.386 + ScopedRoot<String> name_;
65.387 + SourcePosition pos_;
65.388 +
65.389 + protected:
65.390 + ScopedRoot<Type> type_;
65.391 +};
65.392 +
65.393 +class VariableSymbol : public Symbol
65.394 +{
65.395 + public:
65.396 + enum Storage {
65.397 + Unknown,
65.398 + Local,
65.399 + Arg,
65.400 + Heap
65.401 + };
65.402 +
65.403 + public:
65.404 + VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos)
65.405 + : Symbol(scope, name, pos),
65.406 + storage_(Unknown)
65.407 + {
65.408 + }
65.409 +
65.410 + VariableSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type)
65.411 + : Symbol(scope, name, pos),
65.412 + storage_(Unknown)
65.413 + {
65.414 + type_ = type;
65.415 + }
65.416 +
65.417 + Kind kind() const {
65.418 + return kVariable;
65.419 + }
65.420 + void setType(Type *type) {
65.421 + assert(!type_);
65.422 + type_ = type;
65.423 + }
65.424 + void allocate(Storage storage, unsigned slot) {
65.425 + storage_ = storage;
65.426 + slot_ = slot;
65.427 + }
65.428 + Storage storage() const {
65.429 + return storage_;
65.430 + }
65.431 + unsigned slot() const {
65.432 + assert(storage() != Unknown);
65.433 + return slot_;
65.434 + }
65.435 +
65.436 + private:
65.437 + Storage storage_;
65.438 + unsigned slot_;
65.439 +};
65.440 +
65.441 +class TypeSymbol : public Symbol
65.442 +{
65.443 + public:
65.444 + TypeSymbol(Scope *scope, Handle<String> name, Handle<Type> type, Handle<Type> effective)
65.445 + : Symbol(scope, name, SourcePosition()),
65.446 + effective_(effective)
65.447 + {
65.448 + type_ = type;
65.449 + }
65.450 +
65.451 + Kind kind() const {
65.452 + return kType;
65.453 + }
65.454 + Handle<Type> effective() {
65.455 + return effective_;
65.456 + }
65.457 +
65.458 + private:
65.459 + ScopedRoot<Type> effective_;
65.460 +};
65.461 +
65.462 +class FunctionSymbol : public Symbol
65.463 +{
65.464 + public:
65.465 + FunctionSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<FunctionType> type)
65.466 + : Symbol(scope, name, pos)
65.467 + {
65.468 + type_ = type;
65.469 + }
65.470 +
65.471 + Kind kind() const {
65.472 + return kFunction;
65.473 + }
65.474 + FunctionType *type() const {
65.475 + return FunctionType::cast(type_);
65.476 + }
65.477 +};
65.478 +
65.479 +class ConstantSymbol : public Symbol
65.480 +{
65.481 + public:
65.482 + ConstantSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
65.483 + const BoxedPrimitive &prim)
65.484 + : Symbol(scope, name, pos),
65.485 + value_(prim)
65.486 + {
65.487 + type_ = type;
65.488 + }
65.489 +
65.490 + Kind kind() const {
65.491 + return kConstant;
65.492 + }
65.493 + const BoxedPrimitive &value() const {
65.494 + return value_;
65.495 + }
65.496 +
65.497 + private:
65.498 + BoxedPrimitive value_;
65.499 +};
65.500 +
65.501 +class ImportSymbol : public Symbol
65.502 +{
65.503 + public:
65.504 + ImportSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
65.505 + unsigned index)
65.506 + : Symbol(scope, name, pos),
65.507 + index_(index)
65.508 + {
65.509 + type_ = type;
65.510 + }
65.511 +
65.512 + Kind kind() const {
65.513 + return kImport;
65.514 + }
65.515 + unsigned index() const {
65.516 + return index_;
65.517 + }
65.518 +
65.519 + private:
65.520 + unsigned index_;
65.521 +};
65.522 +
65.523 +class ImplicitSymbol : public Symbol
65.524 +{
65.525 + public:
65.526 + ImplicitSymbol(Scope *scope, Handle<String> name, const SourcePosition &pos, Handle<Type> type,
65.527 + unsigned index)
65.528 + : Symbol(scope, name, pos),
65.529 + index_(index),
65.530 + fieldIndex_(unsigned(-1))
65.531 + {
65.532 + type_ = type;
65.533 + }
65.534 +
65.535 + bool bound() const {
65.536 + return fieldIndex_ != unsigned(-1);
65.537 + }
65.538 + Kind kind() const {
65.539 + return kImplicit;
65.540 + }
65.541 + unsigned index() const {
65.542 + return index_;
65.543 + }
65.544 + void bind(unsigned fieldIndex) {
65.545 + fieldIndex_ = fieldIndex;
65.546 + }
65.547 + unsigned fieldIndex() const {
65.548 + assert(bound());
65.549 + return fieldIndex_;
65.550 + }
65.551 +
65.552 + private:
65.553 + unsigned index_;
65.554 + unsigned fieldIndex_;
65.555 +};
65.556 +
65.557 +}
65.558 +
65.559 +#endif // _include_sp2_symbol_h_
66.1 --- a/src/compiler/Token.h Mon Jun 10 00:46:29 2013 +0100
66.2 +++ b/src/compiler/Token.h Mon Jun 10 01:04:43 2013 +0100
66.3 @@ -1,128 +1,128 @@
66.4 -/* vim: set ts=4 sw=4 tw=99 et:
66.5 - *
66.6 - * Copyright (C) 2012 David Anderson
66.7 - *
66.8 - * This file is part of SourcePawn.
66.9 - *
66.10 - * SourcePawn is free software: you can redistribute it and/or modify it under
66.11 - * the terms of the GNU General Public License as published by the Free
66.12 - * Software Foundation, either version 3 of the License, or (at your option)
66.13 - * any later version.
66.14 - *
66.15 - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
66.16 - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
66.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
66.18 - *
66.19 - * You should have received a copy of the GNU General Public License along with
66.20 - * SourcePawn. If not, see http://www.gnu.org/licenses/.
66.21 - */
66.22 -#ifndef _include_jitcraft_token_h_
66.23 -#define _include_jitcraft_token_h_
66.24 -
66.25 -namespace ke {
66.26 -
66.27 -// List of tokens the scanner can recognize.
66.28 -//
66.29 -// Some restrictions:
66.30 -// * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
66.31 -// op-and-assign equivalent.
66.32 -#define TOKENMAP(_) \
66.33 - _(NONE, "<none>") \
66.34 - _(ERROR, "<error>") \
66.35 - _(NEW, "'new'") \
66.36 - _(FOR, "'for'") \
66.37 - _(RETURN, "'return'") \
66.38 - _(NAME, "<name>") \
66.39 - _(INTEGER_LITERAL, "<integer>") \
66.40 - _(HEX_LITERAL, "<hex>") \
66.41 - _(FLOAT_LITERAL, "<float>") \
66.42 - _(STRING_LITERAL, "<string>") \
66.43 - _(IF, "<if>") \
66.44 - _(ELSE, "<else>") \
66.45 - _(ENUM, "<enum>") \
66.46 - _(LABEL, "<label>") \
66.47 - _(WHILE, "<while>") \
66.48 - _(DO, "<do>") \
66.49 - _(BREAK, "<break>") \
66.50 - _(CONTINUE, "<continue>") \
66.51 - _(FORWARD, "<forward>") \
66.52 - _(PUBLIC, "<public>") \
66.53 - _(CONST, "<const>") \
66.54 - _(NATIVE, "<native>") \
66.55 - _(STOCK, "<stock>") \
66.56 - _(TRUE, "<true>") \
66.57 - _(FALSE, "<false>") \
66.58 - _(STRUCT, "<struct>") \
66.59 - _(SWITCH, "<switch>") \
66.60 - _(CASE, "<case>") \
66.61 - _(DEFAULT, "<default>") \
66.62 - _(TYPEDEF, "<typedef>") \
66.63 - _(VOID, "<void>") \
66.64 - _(INT, "<int>") \
66.65 - _(SIZEOF, "<sizeof>") \
66.66 - _(IMPORT, "<import>") \
66.67 - _(FROM, "<from>") \
66.68 - _(ELLIPSES, "...") \
66.69 - _(PLUS, "+") \
66.70 - _(MINUS, "-") \
66.71 - _(STAR, "*") \
66.72 - _(SLASH, "/") \
66.73 - _(PERCENT, "%") \
66.74 - _(AMPERSAND, "&") \
66.75 - _(BITOR, "|") \
66.76 - _(BITXOR, "^") \
66.77 - _(SHR, ">>") \
66.78 - _(USHR, ">>>") \
66.79 - _(SHL, "<<") \
66.80 - _(ASSIGN, "=") \
66.81 - _(SEMICOLON, ";") \
66.82 - _(LBRACE, "{") \
66.83 - _(RBRACE, "}") \
66.84 - _(LPAREN, "(") \
66.85 - _(RPAREN, ")") \
66.86 - _(LBRACKET, "[") \
66.87 - _(RBRACKET, "]") \
66.88 - _(ASSIGN_ADD, "+=") \
66.89 - _(ASSIGN_SUB, "-=") \
66.90 - _(ASSIGN_MUL, "*=") \
66.91 - _(ASSIGN_DIV, "/=") \
66.92 - _(ASSIGN_MOD, "%=") \
66.93 - _(ASSIGN_BITAND, "&=") \
66.94 - _(ASSIGN_BITOR, "|=") \
66.95 - _(ASSIGN_BITXOR, "^=") \
66.96 - _(ASSIGN_SHR, ">>=") \
66.97 - _(ASSIGN_USHR, ">>>=") \
66.98 - _(ASSIGN_SHL, "<<=") \
66.99 - _(INCREMENT, "++") \
66.100 - _(DECREMENT, "--") \
66.101 - _(EQUALS, "==") \
66.102 - _(NOTEQUALS, "!=") \
66.103 - _(LT, "<") \
66.104 - _(LE, "<=") \
66.105 - _(GT, ">") \
66.106 - _(GE, ">=") \
66.107 - _(AND, "&&") \
66.108 - _(OR, "||") \
66.109 - _(COMMA, ",") \
66.110 - _(NOT, "!") \
66.111 - _(TILDE, "~") \
66.112 - _(QMARK, "?") \
66.113 - _(COLON, ":") \
66.114 - _(UNDERSCORE, "_") \
66.115 - _(DOT, ".") \
66.116 - _(EOF, "<end-of-file>")
66.117 -
66.118 -enum TokenKind
66.119 -{
66.120 -# define _(name, str) TOK_##name,
66.121 - TOKENMAP(_)
66.122 -# undef _
66.123 - TOK_BITAND = TOK_AMPERSAND,
66.124 - TOKENS_TOTAL
66.125 -};
66.126 -
66.127 -extern const char *TokenNames[];
66.128 -
66.129 -} // namespace ke
66.130 -
66.131 -#endif //_include_jitcraft_token_h_
66.132 +/* vim: set ts=4 sw=4 tw=99 et:
66.133 + *
66.134 + * Copyright (C) 2012 David Anderson
66.135 + *
66.136 + * This file is part of SourcePawn.
66.137 + *
66.138 + * SourcePawn is free software: you can redistribute it and/or modify it under
66.139 + * the terms of the GNU General Public License as published by the Free
66.140 + * Software Foundation, either version 3 of the License, or (at your option)
66.141 + * any later version.
66.142 + *
66.143 + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
66.144 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
66.145 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
66.146 + *
66.147 + * You should have received a copy of the GNU General Public License along with
66.148 + * SourcePawn. If not, see http://www.gnu.org/licenses/.
66.149 + */
66.150 +#ifndef _include_jitcraft_token_h_
66.151 +#define _include_jitcraft_token_h_
66.152 +
66.153 +namespace ke {
66.154 +
66.155 +// List of tokens the scanner can recognize.
66.156 +//
66.157 +// Some restrictions:
66.158 +// * (ASSIGN_ADD - TOK_PLUS) must be the delta between an operator and its
66.159 +// op-and-assign equivalent.
66.160 +#define TOKENMAP(_) \
66.161 + _(NONE, "<none>") \
66.162 + _(ERROR, "<error>") \
66.163 + _(NEW, "'new'") \
66.164 + _(FOR, "'for'") \
66.165 + _(RETURN, "'return'") \
66.166 + _(NAME, "<name>") \
66.167 + _(INTEGER_LITERAL, "<integer>") \
66.168 + _(HEX_LITERAL, "<hex>") \
66.169 + _(FLOAT_LITERAL, "<float>") \
66.170 + _(STRING_LITERAL, "<string>") \
66.171 + _(IF, "<if>") \
66.172 + _(ELSE, "<else>") \
66.173 + _(ENUM, "<enum>") \
66.174 + _(LABEL, "<label>") \
66.175 + _(WHILE, "<while>") \
66.176 + _(DO, "<do>") \
66.177 + _(BREAK, "<break>") \
66.178 + _(CONTINUE, "<continue>") \
66.179 + _(FORWARD, "<forward>") \
66.180 + _(PUBLIC, "<public>") \
66.181 + _(CONST, "<const>") \
66.182 + _(NATIVE, "<native>") \
66.183 + _(STOCK, "<stock>") \
66.184 + _(TRUE, "<true>") \
66.185 + _(FALSE, "<false>") \
66.186 + _(STRUCT, "<struct>") \
66.187 + _(SWITCH, "<switch>") \
66.188 + _(CASE, "<case>") \
66.189 + _(DEFAULT, "<default>") \
66.190 + _(TYPEDEF, "<typedef>") \
66.191 + _(VOID, "<void>") \
66.192 + _(INT, "<int>") \
66.193 + _(SIZEOF, "<sizeof>") \
66.194 + _(IMPORT, "<import>") \
66.195 + _(FROM, "<from>") \
66.196 + _(ELLIPSES, "...") \
66.197 + _(PLUS, "+") \
66.198 + _(MINUS, "-") \
66.199 + _(STAR, "*") \
66.200 + _(SLASH, "/") \
66.201 + _(PERCENT, "%") \
66.202 + _(AMPERSAND, "&") \
66.203 + _(BITOR, "|") \
66.204 + _(BITXOR, "^") \
66.205 + _(SHR, ">>") \
66.206 + _(USHR, ">>>") \
66.207 + _(SHL, "<<") \
66.208 + _(ASSIGN, "=") \
66.209 + _(SEMICOLON, ";") \
66.210 + _(LBRACE, "{") \
66.211 + _(RBRACE, "}") \
66.212 + _(LPAREN, "(") \
66.213 + _(RPAREN, ")") \
66.214 + _(LBRACKET, "[") \
66.215 + _(RBRACKET, "]") \
66.216 + _(ASSIGN_ADD, "+=") \
66.217 + _(ASSIGN_SUB, "-=") \
66.218 + _(ASSIGN_MUL, "*=") \
66.219 + _(ASSIGN_DIV, "/=") \
66.220 + _(ASSIGN_MOD, "%=") \
66.221 + _(ASSIGN_BITAND, "&=") \
66.222 + _(ASSIGN_BITOR, "|=") \
66.223 + _(ASSIGN_BITXOR, "^=") \
66.224 + _(ASSIGN_SHR, ">>=") \
66.225 + _(ASSIGN_USHR, ">>>=") \
66.226 + _(ASSIGN_SHL, "<<=") \
66.227 + _(INCREMENT, "++") \
66.228 + _(DECREMENT, "--") \
66.229 + _(EQUALS, "==") \
66.230 + _(NOTEQUALS, "!=") \
66.231 + _(LT, "<") \
66.232 + _(LE, "<=") \
66.233 + _(GT, ">") \
66.234 + _(GE, ">=") \
66.235 + _(AND, "&&") \
66.236 + _(OR, "||") \
66.237 + _(COMMA, ",") \
66.238 + _(NOT, "!") \
66.239 + _(TILDE, "~") \
66.240 + _(QMARK, "?") \
66.241 + _(COLON, ":") \
66.242 + _(UNDERSCORE, "_") \
66.243 + _(DOT, ".") \
66.244 + _(EOF, "<end-of-file>")
66.245 +
66.246 +enum TokenKind
66.247 +{
66.248 +# define _(name, str) TOK_##name,
66.249 + TOKENMAP(_)
66.250 +# undef _
66.251 + TOK_BITAND = TOK_AMPERSAND,
66.252 + TOKENS_TOTAL
66.253 +};
66.254 +
66.255 +extern const char *TokenNames[];
66.256 +
66.257 +} // namespace ke
66.258 +
66.259 +#endif //_include_jitcraft_token_h_
67.1 --- a/tests/basic/assignadd.out Mon Jun 10 00:46:29 2013 +0100
67.2 +++ b/tests/basic/assignadd.out Mon Jun 10 01:04:43 2013 +0100
67.3 @@ -1,1 +1,1 @@
67.4 -1683
67.5 +1683
68.1 --- a/tests/basic/assignadd.sp Mon Jun 10 00:46:29 2013 +0100
68.2 +++ b/tests/basic/assignadd.sp Mon Jun 10 01:04:43 2013 +0100
68.3 @@ -1,10 +1,10 @@
68.4 -native PrintNum(num);
68.5 -
68.6 -public main()
68.7 -{
68.8 - new x[3];
68.9 - for (new i = 0; i < 100; i += 3) {
68.10 - x[2] += i;
68.11 - }
68.12 - PrintNum(x[2]);
68.13 -}
68.14 +native PrintNum(num);
68.15 +
68.16 +public main()
68.17 +{
68.18 + new x[3];
68.19 + for (new i = 0; i < 100; i += 3) {
68.20 + x[2] += i;
68.21 + }
68.22 + PrintNum(x[2]);
68.23 +}
69.1 --- a/tests/basic/bitops.out Mon Jun 10 00:46:29 2013 +0100
69.2 +++ b/tests/basic/bitops.out Mon Jun 10 01:04:43 2013 +0100
69.3 @@ -1,1 +1,1 @@
69.4 -35503
69.5 +35503
70.1 --- a/tests/basic/bitops.sp Mon Jun 10 00:46:29 2013 +0100
70.2 +++ b/tests/basic/bitops.sp Mon Jun 10 01:04:43 2013 +0100
70.3 @@ -1,16 +1,16 @@
70.4 -native PrintNum(num);
70.5 -
70.6 -public main()
70.7 -{
70.8 - new result = 5192342;
70.9 - for (new i = 0; i < 1000; i = i + 1) {
70.10 - result = result | i;
70.11 - result = result & 9129345;
70.12 - result = result ^ (i * 73);
70.13 -
70.14 - new bit = result & 1;
70.15 - result = (result >>> 1) | (bit << 31);
70.16 - result = result | (i >> 6);
70.17 - }
70.18 - PrintNum(result);
70.19 -}
70.20 +native PrintNum(num);
70.21 +
70.22 +public main()
70.23 +{
70.24 + new result = 5192342;
70.25 + for (new i = 0; i < 1000; i = i + 1) {
70.26 + result = result | i;
70.27 + result = result & 9129345;
70.28 + result = result ^ (i * 73);
70.29 +
70.30 + new bit = result & 1;
70.31 + result = (result >>> 1) | (bit << 31);
70.32 + result = result | (i >> 6);
70.33 + }
70.34 + PrintNum(result);
70.35 +}
71.1 --- a/tests/basic/break-continue-in-for.out Mon Jun 10 00:46:29 2013 +0100
71.2 +++ b/tests/basic/break-continue-in-for.out Mon Jun 10 01:04:43 2013 +0100
71.3 @@ -1,1 +1,1 @@
71.4 -58
71.5 +58
72.1 --- a/tests/basic/break-continue-in-for.sp Mon Jun 10 00:46:29 2013 +0100
72.2 +++ b/tests/basic/break-continue-in-for.sp Mon Jun 10 01:04:43 2013 +0100
72.3 @@ -1,15 +1,15 @@
72.4 -native PrintNum(num);
72.5 -
72.6 -public main()
72.7 -{
72.8 - new i;
72.9 - for (; i < 100; i = i + 1) {
72.10 - if (i >= 57)
72.11 - break;
72.12 - if (i >= 26) {
72.13 - i = i + 1;
72.14 - continue;
72.15 - }
72.16 - }
72.17 - PrintNum(i);
72.18 -}
72.19 +native PrintNum(num);
72.20 +
72.21 +public main()
72.22 +{
72.23 + new i;
72.24 + for (; i < 100; i = i + 1) {
72.25 + if (i >= 57)
72.26 + break;
72.27 + if (i >= 26) {
72.28 + i = i + 1;
72.29 + continue;
72.30 + }
72.31 + }
72.32 + PrintNum(i);
72.33 +}
73.1 --- a/tests/basic/const-arg-1.err Mon Jun 10 00:46:29 2013 +0100
73.2 +++ b/tests/basic/const-arg-1.err Mon Jun 10 01:04:43 2013 +0100
73.3 @@ -1,1 +1,1 @@
73.4 - line 3, col 12: cannot change constant value or structure
73.5 + line 3, col 12: cannot change constant value or structure
74.1 --- a/tests/basic/const-arg-1.sp Mon Jun 10 00:46:29 2013 +0100
74.2 +++ b/tests/basic/const-arg-1.sp Mon Jun 10 01:04:43 2013 +0100
74.3 @@ -1,4 +1,4 @@
74.4 -f(const char:text[])
74.5 -{
74.6 - text[0] = 0;
74.7 -}
74.8 +f(const char:text[])
74.9 +{
74.10 + text[0] = 0;
74.11 +}
75.1 --- a/tests/basic/const-arg-2.err Mon Jun 10 00:46:29 2013 +0100
75.2 +++ b/tests/basic/const-arg-2.err Mon Jun 10 01:04:43 2013 +0100
75.3 @@ -1,1 +1,1 @@
75.4 - line 1, col 7: const parameters must be arrays or structs
75.5 + line 1, col 7: const parameters must be arrays or structs
76.1 --- a/tests/basic/const-arg-2.sp Mon Jun 10 00:46:29 2013 +0100
76.2 +++ b/tests/basic/const-arg-2.sp Mon Jun 10 01:04:43 2013 +0100
76.3 @@ -1,3 +1,3 @@
76.4 -f(const a)
76.5 -{
76.6 -}
76.7 +f(const a)
76.8 +{
76.9 +}
77.1 --- a/tests/basic/const-arg-3.err Mon Jun 10 00:46:29 2013 +0100
77.2 +++ b/tests/basic/const-arg-3.err Mon Jun 10 01:04:43 2013 +0100
77.3 @@ -1,1 +1,1 @@
77.4 - line 1, col 7: constant outparams are not allowed
77.5 + line 1, col 7: constant outparams are not allowed
78.1 --- a/tests/basic/const-arg-3.sp Mon Jun 10 00:46:29 2013 +0100
78.2 +++ b/tests/basic/const-arg-3.sp Mon Jun 10 01:04:43 2013 +0100
78.3 @@ -1,3 +1,3 @@
78.4 -f(const &a)
78.5 -{
78.6 -}
78.7 +f(const &a)
78.8 +{
78.9 +}
79.1 --- a/tests/basic/const-arg-4.err Mon Jun 10 00:46:29 2013 +0100
79.2 +++ b/tests/basic/const-arg-4.err Mon Jun 10 01:04:43 2013 +0100
79.3 @@ -1,1 +1,1 @@
79.4 - line 8, col 7: type mismatch (expected 'char[]', got 'const char[]')
79.5 + line 8, col 7: type mismatch (expected 'char[]', got 'const char[]')
80.1 --- a/tests/basic/const-arg-4.sp Mon Jun 10 00:46:29 2013 +0100
80.2 +++ b/tests/basic/const-arg-4.sp Mon Jun 10 01:04:43 2013 +0100
80.3 @@ -1,9 +1,9 @@
80.4 -f(char:text[])
80.5 -{
80.6 -}
80.7 -
80.8 -main()
80.9 -{
80.10 - const char:text[] = "";
80.11 - f(text);
80.12 -}
80.13 +f(char:text[])
80.14 +{
80.15 +}
80.16 +
80.17 +main()
80.18 +{
80.19 + const char:text[] = "";
80.20 + f(text);
80.21 +}
81.1 --- a/tests/basic/const-arg-5.out Mon Jun 10 00:46:29 2013 +0100
81.2 +++ b/tests/basic/const-arg-5.out Mon Jun 10 01:04:43 2013 +0100
81.3 @@ -1,1 +1,1 @@
81.4 -9798
81.5 +9798
82.1 --- a/tests/basic/const-arg-5.sp Mon Jun 10 00:46:29 2013 +0100
82.2 +++ b/tests/basic/const-arg-5.sp Mon Jun 10 01:04:43 2013 +0100
82.3 @@ -1,14 +1,14 @@
82.4 -native PrintNum(num);
82.5 -
82.6 -
82.7 -f(const char:text[])
82.8 -{
82.9 - PrintNum(text[0]);
82.10 -}
82.11 -
82.12 -public main()
82.13 -{
82.14 - new char:q[20] = "blub";
82.15 - f("asdf");
82.16 - f(q);
82.17 -}
82.18 +native PrintNum(num);
82.19 +
82.20 +
82.21 +f(const char:text[])
82.22 +{
82.23 + PrintNum(text[0]);
82.24 +}
82.25 +
82.26 +public main()
82.27 +{
82.28 + new char:q[20] = "blub";
82.29 + f("asdf");
82.30 + f(q);
82.31 +}
83.1 --- a/tests/basic/const-global-1.err Mon Jun 10 00:46:29 2013 +0100
83.2 +++ b/tests/basic/const-global-1.err Mon Jun 10 01:04:43 2013 +0100
83.3 @@ -1,1 +1,1 @@
83.4 - line 4, col 7: cannot change constant value or structure
83.5 + line 4, col 7: cannot change constant value or structure
84.1 --- a/tests/basic/const-global-1.sp Mon Jun 10 00:46:29 2013 +0100
84.2 +++ b/tests/basic/const-global-1.sp Mon Jun 10 01:04:43 2013 +0100
84.3 @@ -1,5 +1,5 @@
84.4 -const a = 5;
84.5 -public main()
84.6 -{
84.7 - a = 10;
84.8 -}
84.9 +const a = 5;
84.10 +public main()
84.11 +{
84.12 + a = 10;
84.13 +}
85.1 --- a/tests/basic/const-global-2.err Mon Jun 10 00:46:29 2013 +0100
85.2 +++ b/tests/basic/const-global-2.err Mon Jun 10 01:04:43 2013 +0100
85.3 @@ -1,1 +1,1 @@
85.4 - line 5, col 12: cannot change constant value or structure
85.5 + line 5, col 12: cannot change constant value or structure
86.1 --- a/tests/basic/const-global-2.sp Mon Jun 10 00:46:29 2013 +0100
86.2 +++ b/tests/basic/const-global-2.sp Mon Jun 10 01:04:43 2013 +0100
86.3 @@ -1,6 +1,6 @@
86.4 -const char:text[] = "Adsf";
86.5 -
86.6 -public main()
86.7 -{
86.8 - text[0] = 0;
86.9 -}
86.10 +const char:text[] = "Adsf";
86.11 +
86.12 +public main()
86.13 +{
86.14 + text[0] = 0;
86.15 +}
87.1 --- a/tests/basic/const-global-3.err Mon Jun 10 00:46:29 2013 +0100
87.2 +++ b/tests/basic/const-global-3.err Mon Jun 10 01:04:43 2013 +0100
87.3 @@ -1,1 +1,1 @@
87.4 - line 4, col 10: cannot change constant value or structure
87.5 + line 4, col 10: cannot change constant value or structure
88.1 --- a/tests/basic/const-global-3.sp Mon Jun 10 00:46:29 2013 +0100
88.2 +++ b/tests/basic/const-global-3.sp Mon Jun 10 01:04:43 2013 +0100
88.3 @@ -1,5 +1,5 @@
88.4 -const char:text[] = "";
88.5 -public main()
88.6 -{
88.7 - text = "a";
88.8 -}
88.9 +const char:text[] = "";
88.10 +public main()
88.11 +{
88.12 + text = "a";
88.13 +}
89.1 --- a/tests/basic/const-local-1.err Mon Jun 10 00:46:29 2013 +0100
89.2 +++ b/tests/basic/const-local-1.err Mon Jun 10 01:04:43 2013 +0100
89.3 @@ -1,1 +1,1 @@
89.4 - line 4, col 7: cannot change constant value or structure
89.5 + line 4, col 7: cannot change constant value or structure
90.1 --- a/tests/basic/const-local-1.sp Mon Jun 10 00:46:29 2013 +0100
90.2 +++ b/tests/basic/const-local-1.sp Mon Jun 10 01:04:43 2013 +0100
90.3 @@ -1,6 +1,6 @@
90.4 -public main()
90.5 -{
90.6 - const a = 5;
90.7 - a = 10;
90.8 -}
90.9 -
90.10 +public main()
90.11 +{
90.12 + const a = 5;
90.13 + a = 10;
90.14 +}
90.15 +
91.1 --- a/tests/basic/const-local-2.err Mon Jun 10 00:46:29 2013 +0100
91.2 +++ b/tests/basic/const-local-2.err Mon Jun 10 01:04:43 2013 +0100
91.3 @@ -1,1 +1,1 @@
91.4 - line 4, col 12: cannot change constant value or structure
91.5 + line 4, col 12: cannot change constant value or structure
92.1 --- a/tests/basic/const-local-2.sp Mon Jun 10 00:46:29 2013 +0100
92.2 +++ b/tests/basic/const-local-2.sp Mon Jun 10 01:04:43 2013 +0100
92.3 @@ -1,5 +1,5 @@
92.4 -public main()
92.5 -{
92.6 - const char:text[] = "hello, gabe newell!";
92.7 - text[5] = 10;
92.8 -}
92.9 +public main()
92.10 +{
92.11 + const char:text[] = "hello, gabe newell!";
92.12 + text[5] = 10;
92.13 +}
93.1 --- a/tests/basic/const-local-3.out Mon Jun 10 00:46:29 2013 +0100
93.2 +++ b/tests/basic/const-local-3.out Mon Jun 10 01:04:43 2013 +0100
93.3 @@ -1,1 +1,1 @@
93.4 -107
93.5 +107
94.1 --- a/tests/basic/const-local-3.sp Mon Jun 10 00:46:29 2013 +0100
94.2 +++ b/tests/basic/const-local-3.sp Mon Jun 10 01:04:43 2013 +0100
94.3 @@ -1,9 +1,9 @@
94.4 -native PrintNum(num);
94.5 -
94.6 -public main()
94.7 -{
94.8 - const char:a[] = "what";
94.9 - const char:b[] = "k";
94.10 - a = b;
94.11 - PrintNum(a[0]);
94.12 -}
94.13 +native PrintNum(num);
94.14 +
94.15 +public main()
94.16 +{
94.17 + const char:a[] = "what";
94.18 + const char:b[] = "k";
94.19 + a = b;
94.20 + PrintNum(a[0]);
94.21 +}
95.1 --- a/tests/basic/continue-in-while.out Mon Jun 10 00:46:29 2013 +0100
95.2 +++ b/tests/basic/continue-in-while.out Mon Jun 10 01:04:43 2013 +0100
95.3 @@ -1,1 +1,1 @@
95.4 -222
95.5 +222
96.1 --- a/tests/basic/continue-in-while.sp Mon Jun 10 00:46:29 2013 +0100
96.2 +++ b/tests/basic/continue-in-while.sp Mon Jun 10 01:04:43 2013 +0100
96.3 @@ -1,13 +1,13 @@
96.4 -native PrintNum(num);
96.5 -
96.6 -public main()
96.7 -{
96.8 - new i = 0;
96.9 - while (1) {
96.10 - i = i + 37;
96.11 - if (i < 200)
96.12 - continue;
96.13 - break;
96.14 - }
96.15 - PrintNum(i);
96.16 -}
96.17 +native PrintNum(num);
96.18 +
96.19 +public main()
96.20 +{
96.21 + new i = 0;
96.22 + while (1) {
96.23 + i = i + 37;
96.24 + if (i < 200)
96.25 + continue;
96.26 + break;
96.27 + }
96.28 + PrintNum(i);
96.29 +}
97.1 --- a/tests/basic/decl-void.err Mon Jun 10 00:46:29 2013 +0100
97.2 +++ b/tests/basic/decl-void.err Mon Jun 10 01:04:43 2013 +0100
97.3 @@ -1,1 +1,1 @@
97.4 - line 1, col 4: expected token '<name>', got '<void>'
97.5 + line 1, col 4: expected token '<name>', got '<void>'
98.1 --- a/tests/basic/decl-void.sp Mon Jun 10 00:46:29 2013 +0100
98.2 +++ b/tests/basic/decl-void.sp Mon Jun 10 01:04:43 2013 +0100
98.3 @@ -1,2 +1,2 @@
98.4 -new void:x;
98.5 -
98.6 +new void:x;
98.7 +
99.1 --- a/tests/basic/dependent-strings.out Mon Jun 10 00:46:29 2013 +0100
99.2 +++ b/tests/basic/dependent-strings.out Mon Jun 10 01:04:43 2013 +0100
99.3 @@ -1,2 +1,2 @@
99.4 -Pab
99.5 -ake
99.6 +Pab
99.7 +ake
100.1 --- a/tests/basic/dependent-strings.sp Mon Jun 10 00:46:29 2013 +0100
100.2 +++ b/tests/basic/dependent-strings.sp Mon Jun 10 01:04:43 2013 +0100
100.3 @@ -1,20 +1,20 @@
100.4 -native PrintString(const char:text[]);
100.5 -
100.6 -f(char:str[])
100.7 -{
100.8 - str[0] = 80;
100.9 -}
100.10 -
100.11 -public main()
100.12 -{
100.13 - new char:fixed[100] = "crab\n";
100.14 - new char:dynamo[];
100.15 -
100.16 - dynamo = "cake\n";
100.17 -
100.18 - f(fixed[1]);
100.19 - f(dynamo[1]);
100.20 - PrintString(fixed[1]);
100.21 - PrintString(dynamo[1]);
100.22 -}
100.23 -
100.24 +native PrintString(const char:text[]);
100.25 +
100.26 +f(char:str[])
100.27 +{
100.28 + str[0] = 80;
100.29 +}
100.30 +
100.31 +public main()
100.32 +{
100.33 + new char:fixed[100] = "crab\n";
100.34 + new char:dynamo[];
100.35 +
100.36 + dynamo = "cake\n";
100.37 +
100.38 + f(fixed[1]);
100.39 + f(dynamo[1]);
100.40 + PrintString(fixed[1]);
100.41 + PrintString(dynamo[1]);
100.42 +}
100.43 +
101.1 --- a/tests/basic/divide-by-zero.err Mon Jun 10 00:46:29 2013 +0100
101.2 +++ b/tests/basic/divide-by-zero.err Mon Jun 10 01:04:43 2013 +0100
101.3 @@ -1,3 +1,3 @@
101.4 -Uncaught exception: integer divide by zero
101.5 -[0] f (divide-by-zero.sp line 1)
101.6 -[1] main (divide-by-zero.sp line 3)
101.7 +Uncaught exception: integer divide by zero
101.8 +[0] f (divide-by-zero.sp line 1)
101.9 +[1] main (divide-by-zero.sp line 3)
102.1 --- a/tests/basic/divide-by-zero.sp Mon Jun 10 00:46:29 2013 +0100
102.2 +++ b/tests/basic/divide-by-zero.sp Mon Jun 10 01:04:43 2013 +0100
102.3 @@ -1,14 +1,14 @@
102.4 -native PrintToNum(num);
102.5 -
102.6 -f(a, b) {
102.7 - return a /b ;
102.8 -}
102.9 -
102.10 -public main()
102.11 -{
102.12 - for (new i = 0; i < 100; i++) {
102.13 - f(i + 5, i - 8);
102.14 - }
102.15 - return 10;
102.16 -}
102.17 -
102.18 +native PrintToNum(num);
102.19 +
102.20 +f(a, b) {
102.21 + return a /b ;
102.22 +}
102.23 +
102.24 +public main()
102.25 +{
102.26 + for (new i = 0; i < 100; i++) {
102.27 + f(i + 5, i - 8);
102.28 + }
102.29 + return 10;
102.30 +}
102.31 +
103.1 --- a/tests/basic/do.out Mon Jun 10 00:46:29 2013 +0100
103.2 +++ b/tests/basic/do.out Mon Jun 10 01:04:43 2013 +0100
103.3 @@ -1,1 +1,1 @@
103.4 -37
103.5 +37
104.1 --- a/tests/basic/do.sp Mon Jun 10 00:46:29 2013 +0100
104.2 +++ b/tests/basic/do.sp Mon Jun 10 01:04:43 2013 +0100
104.3 @@ -1,10 +1,10 @@
104.4 -native PrintNum(num);
104.5 -
104.6 -public main()
104.7 -{
104.8 - new i = 0;
104.9 - do {
104.10 - i = i + 37;
104.11 - } while (i < 5);
104.12 - PrintNum(i);
104.13 -}
104.14 +native PrintNum(num);
104.15 +
104.16 +public main()
104.17 +{
104.18 + new i = 0;
104.19 + do {
104.20 + i = i + 37;
104.21 + } while (i < 5);
104.22 + PrintNum(i);
104.23 +}
105.1 --- a/tests/basic/enum-bad.err Mon Jun 10 00:46:29 2013 +0100
105.2 +++ b/tests/basic/enum-bad.err Mon Jun 10 01:04:43 2013 +0100
105.3 @@ -1,1 +1,1 @@
105.4 - line 6, col 13: cannot coerce type 'int' to type 'X'
105.5 + line 6, col 13: cannot coerce type 'int' to type 'X'
106.1 --- a/tests/basic/enum-bad.sp Mon Jun 10 00:46:29 2013 +0100
106.2 +++ b/tests/basic/enum-bad.sp Mon Jun 10 01:04:43 2013 +0100
106.3 @@ -1,7 +1,7 @@
106.4 -enum X {
106.5 -};
106.6 -
106.7 -public main()
106.8 -{
106.9 - new X:x = 5;
106.10 -}
106.11 +enum X {
106.12 +};
106.13 +
106.14 +public main()
106.15 +{
106.16 + new X:x = 5;
106.17 +}
107.1 --- a/tests/basic/enum-redecl.err Mon Jun 10 00:46:29 2013 +0100
107.2 +++ b/tests/basic/enum-redecl.err Mon Jun 10 01:04:43 2013 +0100
107.3 @@ -1,1 +1,1 @@
107.4 - line 4, col 4: name 'Y' was redeclared (previous at line 2, col 4)
107.5 + line 4, col 4: name 'Y' was redeclared (previous at line 2, col 4)
108.1 --- a/tests/basic/enum-redecl.sp Mon Jun 10 00:46:29 2013 +0100
108.2 +++ b/tests/basic/enum-redecl.sp Mon Jun 10 01:04:43 2013 +0100
108.3 @@ -1,6 +1,6 @@
108.4 -enum X {
108.5 - Y,
108.6 - Z,
108.7 - Y
108.8 -};
108.9 -
108.10 +enum X {
108.11 + Y,
108.12 + Z,
108.13 + Y
108.14 +};
108.15 +
109.1 --- a/tests/basic/enum-use.out Mon Jun 10 00:46:29 2013 +0100
109.2 +++ b/tests/basic/enum-use.out Mon Jun 10 01:04:43 2013 +0100
109.3 @@ -1,1 +1,1 @@
109.4 -01570157
109.5 +01570157
110.1 --- a/tests/basic/enum-use.sp Mon Jun 10 00:46:29 2013 +0100
110.2 +++ b/tests/basic/enum-use.sp Mon Jun 10 01:04:43 2013 +0100
110.3 @@ -1,28 +1,28 @@
110.4 -native PrintNum(num);
110.5 -
110.6 -enum Crab {
110.7 - CrabOne,
110.8 - CrabTwo,
110.9 - CrabThree=5,
110.10 - CrabFour=7
110.11 -};
110.12 -
110.13 -enum {
110.14 - CrabFive,
110.15 - CrabSix,
110.16 - CrabSeven=5,
110.17 - CrabEight=7
110.18 -};
110.19 -
110.20 -public main()
110.21 -{
110.22 - PrintNum(CrabOne);
110.23 - PrintNum(CrabTwo);
110.24 - PrintNum(CrabThree);
110.25 - PrintNum(CrabFour);
110.26 - PrintNum(CrabFive);
110.27 - PrintNum(CrabSix);
110.28 - PrintNum(CrabSeven);
110.29 - PrintNum(CrabEight);
110.30 -}
110.31 -
110.32 +native PrintNum(num);
110.33 +
110.34 +enum Crab {
110.35 + CrabOne,
110.36 + CrabTwo,
110.37 + CrabThree=5,
110.38 + CrabFour=7
110.39 +};
110.40 +
110.41 +enum {
110.42 + CrabFive,
110.43 + CrabSix,
110.44 + CrabSeven=5,
110.45 + CrabEight=7
110.46 +};
110.47 +
110.48 +public main()
110.49 +{
110.50 + PrintNum(CrabOne);
110.51 + PrintNum(CrabTwo);
110.52 + PrintNum(CrabThree);
110.53 + PrintNum(CrabFour);
110.54 + PrintNum(CrabFive);
110.55 + PrintNum(CrabSix);
110.56 + PrintNum(CrabSeven);
110.57 + PrintNum(CrabEight);
110.58 +}
110.59 +
111.1 --- a/tests/basic/float-arrays.out Mon Jun 10 00:46:29 2013 +0100
111.2 +++ b/tests/basic/float-arrays.out Mon Jun 10 01:04:43 2013 +0100
111.3 @@ -1,1 +1,1 @@
111.4 -11.500000
111.5 +11.500000
112.1 --- a/tests/basic/float-arrays.sp Mon Jun 10 00:46:29 2013 +0100
112.2 +++ b/tests/basic/float-arrays.sp Mon Jun 10 01:04:43 2013 +0100
112.3 @@ -1,9 +1,9 @@
112.4 -native PrintFloat(float:num);
112.5 -
112.6 -public main()
112.7 -{
112.8 - new float:vec[3];
112.9 - for (new i = 0; i < 3; i = i + 1)
112.10 - vec[i] = i + 9.5;
112.11 - PrintFloat(vec[2]);
112.12 -}
112.13 +native PrintFloat(float:num);
112.14 +
112.15 +public main()
112.16 +{
112.17 + new float:vec[3];
112.18 + for (new i = 0; i < 3; i = i + 1)
112.19 + vec[i] = i + 9.5;
112.20 + PrintFloat(vec[2]);
112.21 +}
113.1 --- a/tests/basic/floats.out Mon Jun 10 00:46:29 2013 +0100
113.2 +++ b/tests/basic/floats.out Mon Jun 10 01:04:43 2013 +0100
113.3 @@ -1,1 +1,1 @@
113.4 -5012.000000
113.5 +5012.000000
114.1 --- a/tests/basic/floats.sp Mon Jun 10 00:46:29 2013 +0100
114.2 +++ b/tests/basic/floats.sp Mon Jun 10 01:04:43 2013 +0100
114.3 @@ -1,9 +1,9 @@
114.4 -native PrintFloat(float:num);
114.5 -
114.6 -public main()
114.7 -{
114.8 - new float:f = 12.0;
114.9 - for (new i = 0; i < 100; i = i + 1)
114.10 - f = f + 0.5 + i;
114.11 - PrintFloat(f);
114.12 -}
114.13 +native PrintFloat(float:num);
114.14 +
114.15 +public main()
114.16 +{
114.17 + new float:f = 12.0;
114.18 + for (new i = 0; i < 100; i = i + 1)
114.19 + f = f + 0.5 + i;
114.20 + PrintFloat(f);
114.21 +}
115.1 --- a/tests/basic/import-sysroot-all.out Mon Jun 10 00:46:29 2013 +0100
115.2 +++ b/tests/basic/import-sysroot-all.out Mon Jun 10 01:04:43 2013 +0100
115.3 @@ -1,1 +1,1 @@
115.4 -5 is 5.000000
115.5 +5 is 5.000000
116.1 --- a/tests/basic/import-sysroot-all.sp Mon Jun 10 00:46:29 2013 +0100
116.2 +++ b/tests/basic/import-sysroot-all.sp Mon Jun 10 01:04:43 2013 +0100
116.3 @@ -1,9 +1,9 @@
116.4 -from shell import *;
116.5 -
116.6 -public main()
116.7 -{
116.8 - PrintNum(5);
116.9 - PrintString(" is ");
116.10 - PrintFloat(5.0);
116.11 -}
116.12 -
116.13 +from shell import *;
116.14 +
116.15 +public main()
116.16 +{
116.17 + PrintNum(5);
116.18 + PrintString(" is ");
116.19 + PrintFloat(5.0);
116.20 +}
116.21 +
117.1 --- a/tests/basic/import-sysroot-module.out Mon Jun 10 00:46:29 2013 +0100
117.2 +++ b/tests/basic/import-sysroot-module.out Mon Jun 10 01:04:43 2013 +0100
117.3 @@ -1,1 +1,1 @@
117.4 -5 is 5.000000
117.5 +5 is 5.000000
118.1 --- a/tests/basic/import-sysroot-module.sp Mon Jun 10 00:46:29 2013 +0100
118.2 +++ b/tests/basic/import-sysroot-module.sp Mon Jun 10 01:04:43 2013 +0100
118.3 @@ -1,9 +1,9 @@
118.4 -import shell;
118.5 -
118.6 -public main()
118.7 -{
118.8 - shell.PrintNum(5);
118.9 - shell.PrintString(" is ");
118.10 - shell.PrintFloat(5.0);
118.11 -}
118.12 -
118.13 +import shell;
118.14 +
118.15 +public main()
118.16 +{
118.17 + shell.PrintNum(5);
118.18 + shell.PrintString(" is ");
118.19 + shell.PrintFloat(5.0);
118.20 +}
118.21 +
119.1 --- a/tests/basic/import-sysroot-select.out Mon Jun 10 00:46:29 2013 +0100
119.2 +++ b/tests/basic/import-sysroot-select.out Mon Jun 10 01:04:43 2013 +0100
119.3 @@ -1,1 +1,1 @@
119.4 -5 is 5.000000
119.5 +5 is 5.000000
120.1 --- a/tests/basic/import-sysroot-select.sp Mon Jun 10 00:46:29 2013 +0100
120.2 +++ b/tests/basic/import-sysroot-select.sp Mon Jun 10 01:04:43 2013 +0100
120.3 @@ -1,9 +1,9 @@
120.4 -from shell import PrintNum, PrintString, PrintFloat;
120.5 -
120.6 -public main()
120.7 -{
120.8 - PrintNum(5);
120.9 - PrintString(" is ");
120.10 - PrintFloat(5.0);
120.11 -}
120.12 -
120.13 +from shell import PrintNum, PrintString, PrintFloat;
120.14 +
120.15 +public main()
120.16 +{
120.17 + PrintNum(5);
120.18 + PrintString(" is ");
120.19 + PrintFloat(5.0);
120.20 +}
120.21 +
121.1 --- a/tests/basic/import_enum_a.out Mon Jun 10 00:46:29 2013 +0100
121.2 +++ b/tests/basic/import_enum_a.out Mon Jun 10 01:04:43 2013 +0100
121.3 @@ -1,1 +1,1 @@
121.4 -2
121.5 +2
122.1 --- a/tests/basic/import_enum_a.sp Mon Jun 10 00:46:29 2013 +0100
122.2 +++ b/tests/basic/import_enum_a.sp Mon Jun 10 01:04:43 2013 +0100
122.3 @@ -1,10 +1,10 @@
122.4 -import shell;
122.5 -import import_enum_b.*;
122.6 -
122.7 -public main()
122.8 -{
122.9 - new Crab:crab = TotalCrab;
122.10 -
122.11 - shell.PrintNum(crab);
122.12 -}
122.13 -
122.14 +import shell;
122.15 +import import_enum_b.*;
122.16 +
122.17 +public main()
122.18 +{
122.19 + new Crab:crab = TotalCrab;
122.20 +
122.21 + shell.PrintNum(crab);
122.22 +}
122.23 +
123.1 --- a/tests/basic/import_enum_b.sp Mon Jun 10 00:46:29 2013 +0100
123.2 +++ b/tests/basic/import_enum_b.sp Mon Jun 10 01:04:43 2013 +0100
123.3 @@ -1,7 +1,7 @@
123.4 -public enum Crab
123.5 -{
123.6 - A,
123.7 - B,
123.8 - TotalCrab
123.9 -};
123.10 -
123.11 +public enum Crab
123.12 +{
123.13 + A,
123.14 + B,
123.15 + TotalCrab
123.16 +};
123.17 +
124.1 --- a/tests/basic/passarray.out Mon Jun 10 00:46:29 2013 +0100
124.2 +++ b/tests/basic/passarray.out Mon Jun 10 01:04:43 2013 +0100
124.3 @@ -1,1 +1,1 @@
124.4 -037
124.5 +037
125.1 --- a/tests/basic/passarray.sp Mon Jun 10 00:46:29 2013 +0100
125.2 +++ b/tests/basic/passarray.sp Mon Jun 10 01:04:43 2013 +0100
125.3 @@ -1,23 +1,23 @@
125.4 -native PrintNum(num);
125.5 -
125.6 -f(a[])
125.7 -{
125.8 - return a[3];
125.9 -}
125.10 -
125.11 -g(a[])
125.12 -{
125.13 - a[3] = 7;
125.14 -}
125.15 -
125.16 -public main()
125.17 -{
125.18 - new b[5];
125.19 - b[2] = 3;
125.20 - PrintNum(f(b));
125.21 - b[3] = 3;
125.22 - PrintNum(f(b));
125.23 - g(b);
125.24 - PrintNum(b[3]);
125.25 -}
125.26 -
125.27 +native PrintNum(num);
125.28 +
125.29 +f(a[])
125.30 +{
125.31 + return a[3];
125.32 +}
125.33 +
125.34 +g(a[])
125.35 +{
125.36 + a[3] = 7;
125.37 +}
125.38 +
125.39 +public main()
125.40 +{
125.41 + new b[5];
125.42 + b[2] = 3;
125.43 + PrintNum(f(b));
125.44 + b[3] = 3;
125.45 + PrintNum(f(b));
125.46 + g(b);
125.47 + PrintNum(b[3]);
125.48 +}
125.49 +
126.1 --- a/tests/basic/postinc-array.out Mon Jun 10 00:46:29 2013 +0100
126.2 +++ b/tests/basic/postinc-array.out Mon Jun 10 01:04:43 2013 +0100
126.3 @@ -1,1 +1,1 @@
126.4 -01
126.5 +01
127.1 --- a/tests/basic/postinc-array.sp Mon Jun 10 00:46:29 2013 +0100
127.2 +++ b/tests/basic/postinc-array.sp Mon Jun 10 01:04:43 2013 +0100
127.3 @@ -1,8 +1,8 @@
127.4 -native PrintNum(num);
127.5 -
127.6 -public main()
127.7 -{
127.8 - new x[5];
127.9 - PrintNum(x[3]++);
127.10 - PrintNum(x[3]);
127.11 -}
127.12 +native PrintNum(num);
127.13 +
127.14 +public main()
127.15 +{
127.16 + new x[5];
127.17 + PrintNum(x[3]++);
127.18 + PrintNum(x[3]);
127.19 +}
128.1 --- a/tests/basic/postinc-local.out Mon Jun 10 00:46:29 2013 +0100
128.2 +++ b/tests/basic/postinc-local.out Mon Jun 10 01:04:43 2013 +0100
128.3 @@ -1,1 +1,1 @@
128.4 -01
128.5 +01
129.1 --- a/tests/basic/postinc-local.sp Mon Jun 10 00:46:29 2013 +0100
129.2 +++ b/tests/basic/postinc-local.sp Mon Jun 10 01:04:43 2013 +0100
129.3 @@ -1,8 +1,8 @@
129.4 -native PrintNum(num);
129.5 -
129.6 -public main()
129.7 -{
129.8 - new i = 0;
129.9 - PrintNum(i++);
129.10 - PrintNum(i);
129.11 -}
129.12 +native PrintNum(num);
129.13 +
129.14 +public main()
129.15 +{
129.16 + new i = 0;
129.17 + PrintNum(i++);
129.18 + PrintNum(i);
129.19 +}
130.1 --- a/tests/basic/postinc-ref.out Mon Jun 10 00:46:29 2013 +0100
130.2 +++ b/tests/basic/postinc-ref.out Mon Jun 10 01:04:43 2013 +0100
130.3 @@ -1,1 +1,1 @@
130.4 -01
130.5 +01
131.1 --- a/tests/basic/postinc-ref.sp Mon Jun 10 00:46:29 2013 +0100
131.2 +++ b/tests/basic/postinc-ref.sp Mon Jun 10 01:04:43 2013 +0100
131.3 @@ -1,13 +1,13 @@
131.4 -native PrintNum(num);
131.5 -
131.6 -f(&a)
131.7 -{
131.8 - return a++;
131.9 -}
131.10 -
131.11 -public main()
131.12 -{
131.13 - new i = 0;
131.14 - PrintNum(f(i));
131.15 - PrintNum(i);
131.16 -}
131.17 +native PrintNum(num);
131.18 +
131.19 +f(&a)
131.20 +{
131.21 + return a++;
131.22 +}
131.23 +
131.24 +public main()
131.25 +{
131.26 + new i = 0;
131.27 + PrintNum(f(i));
131.28 + PrintNum(i);
131.29 +}
132.1 --- a/tests/basic/precall-void-used.out Mon Jun 10 00:46:29 2013 +0100
132.2 +++ b/tests/basic/precall-void-used.out Mon Jun 10 01:04:43 2013 +0100
132.3 @@ -1,1 +1,1 @@
132.4 -0
132.5 +0
133.1 --- a/tests/basic/precall-void-used.sp Mon Jun 10 00:46:29 2013 +0100
133.2 +++ b/tests/basic/precall-void-used.sp Mon Jun 10 01:04:43 2013 +0100
133.3 @@ -1,17 +1,17 @@
133.4 -native PrintNum(num);
133.5 -
133.6 -g()
133.7 -{
133.8 - PrintNum(f());
133.9 -}
133.10 -
133.11 -f()
133.12 -{
133.13 - return 0;
133.14 -}
133.15 -
133.16 -public main()
133.17 -{
133.18 - g();
133.19 -}
133.20 -
133.21 +native PrintNum(num);
133.22 +
133.23 +g()
133.24 +{
133.25 + PrintNum(f());
133.26 +}
133.27 +
133.28 +f()
133.29 +{
133.30 + return 0;
133.31 +}
133.32 +
133.33 +public main()
133.34 +{
133.35 + g();
133.36 +}
133.37 +
134.1 --- a/tests/basic/preinc-array.out Mon Jun 10 00:46:29 2013 +0100
134.2 +++ b/tests/basic/preinc-array.out Mon Jun 10 01:04:43 2013 +0100
134.3 @@ -1,1 +1,1 @@
134.4 -1
134.5 +1
135.1 --- a/tests/basic/preinc-array.sp Mon Jun 10 00:46:29 2013 +0100
135.2 +++ b/tests/basic/preinc-array.sp Mon Jun 10 01:04:43 2013 +0100
135.3 @@ -1,7 +1,7 @@
135.4 -native PrintNum(num);
135.5 -
135.6 -public main()
135.7 -{
135.8 - new x[5];
135.9 - PrintNum(++x[3]);
135.10 -}
135.11 +native PrintNum(num);
135.12 +
135.13 +public main()
135.14 +{
135.15 + new x[5];
135.16 + PrintNum(++x[3]);
135.17 +}
136.1 --- a/tests/basic/preinc-local.out Mon Jun 10 00:46:29 2013 +0100
136.2 +++ b/tests/basic/preinc-local.out Mon Jun 10 01:04:43 2013 +0100
136.3 @@ -1,1 +1,1 @@
136.4 -1
136.5 +1
137.1 --- a/tests/basic/preinc-local.sp Mon Jun 10 00:46:29 2013 +0100
137.2 +++ b/tests/basic/preinc-local.sp Mon Jun 10 01:04:43 2013 +0100
137.3 @@ -1,7 +1,7 @@
137.4 -native PrintNum(num);
137.5 -
137.6 -public main()
137.7 -{
137.8 - new i = 0;
137.9 - PrintNum(++i);
137.10 -}
137.11 +native PrintNum(num);
137.12 +
137.13 +public main()
137.14 +{
137.15 + new i = 0;
137.16 + PrintNum(++i);
137.17 +}
138.1 --- a/tests/basic/preinc-ref.out Mon Jun 10 00:46:29 2013 +0100
138.2 +++ b/tests/basic/preinc-ref.out Mon Jun 10 01:04:43 2013 +0100
138.3 @@ -1,1 +1,1 @@
138.4 -11
138.5 +11
139.1 --- a/tests/basic/preinc-ref.sp Mon Jun 10 00:46:29 2013 +0100
139.2 +++ b/tests/basic/preinc-ref.sp Mon Jun 10 01:04:43 2013 +0100
139.3 @@ -1,13 +1,13 @@
139.4 -native PrintNum(num);
139.5 -
139.6 -f(&a)
139.7 -{
139.8 - return ++a;
139.9 -}
139.10 -
139.11 -public main()
139.12 -{
139.13 - new i = 0;
139.14 - PrintNum(f(i));
139.15 - PrintNum(i);
139.16 -}
139.17 +native PrintNum(num);
139.18 +
139.19 +f(&a)
139.20 +{
139.21 + return ++a;
139.22 +}
139.23 +
139.24 +public main()
139.25 +{
139.26 + new i = 0;
139.27 + PrintNum(f(i));
139.28 + PrintNum(i);
139.29 +}
140.1 --- a/tests/basic/recursive_import_1_a.out Mon Jun 10 00:46:29 2013 +0100
140.2 +++ b/tests/basic/recursive_import_1_a.out Mon Jun 10 01:04:43 2013 +0100
140.3 @@ -1,1 +1,1 @@
140.4 -10
140.5 +10
141.1 --- a/tests/basic/recursive_import_1_a.sp Mon Jun 10 00:46:29 2013 +0100
141.2 +++ b/tests/basic/recursive_import_1_a.sp Mon Jun 10 01:04:43 2013 +0100
141.3 @@ -1,9 +1,9 @@
141.4 -from recursive_import_1_b import f;
141.5 -
141.6 -native PrintNum(num);
141.7 -
141.8 -public main()
141.9 -{
141.10 - f();
141.11 -}
141.12 -
141.13 +from recursive_import_1_b import f;
141.14 +
141.15 +native PrintNum(num);
141.16 +
141.17 +public main()
141.18 +{
141.19 + f();
141.20 +}
141.21 +
142.1 --- a/tests/basic/recursive_import_1_b.sp Mon Jun 10 00:46:29 2013 +0100
142.2 +++ b/tests/basic/recursive_import_1_b.sp Mon Jun 10 01:04:43 2013 +0100
142.3 @@ -1,6 +1,6 @@
142.4 -from recursive_import_1_a import PrintNum;
142.5 -
142.6 -public f()
142.7 -{
142.8 - PrintNum(10);
142.9 -}
142.10 +from recursive_import_1_a import PrintNum;
142.11 +
142.12 +public f()
142.13 +{
142.14 + PrintNum(10);
142.15 +}
143.1 --- a/tests/basic/ref-arg.out Mon Jun 10 00:46:29 2013 +0100
143.2 +++ b/tests/basic/ref-arg.out Mon Jun 10 01:04:43 2013 +0100
143.3 @@ -1,1 +1,1 @@
143.4 -122
143.5 +122
144.1 --- a/tests/basic/ref-arg.sp Mon Jun 10 00:46:29 2013 +0100
144.2 +++ b/tests/basic/ref-arg.sp Mon Jun 10 01:04:43 2013 +0100
144.3 @@ -1,20 +1,20 @@
144.4 -native PrintNum(b);
144.5 -
144.6 -f(&a)
144.7 -{
144.8 - for (new i = 0; i < 10; i = i + 1)
144.9 - a = a + i;
144.10 - return 0;
144.11 -}
144.12 -
144.13 -g(&b)
144.14 -{
144.15 - return f(b);
144.16 -}
144.17 -
144.18 -public main()
144.19 -{
144.20 - new b = 77;
144.21 - g(b);
144.22 - PrintNum(b);
144.23 -}
144.24 +native PrintNum(b);
144.25 +
144.26 +f(&a)
144.27 +{
144.28 + for (new i = 0; i < 10; i = i + 1)
144.29 + a = a + i;
144.30 + return 0;
144.31 +}
144.32 +
144.33 +g(&b)
144.34 +{
144.35 + return f(b);
144.36 +}
144.37 +
144.38 +public main()
144.39 +{
144.40 + new b = 77;
144.41 + g(b);
144.42 + PrintNum(b);
144.43 +}
145.1 --- a/tests/basic/ref-expr.out Mon Jun 10 00:46:29 2013 +0100
145.2 +++ b/tests/basic/ref-expr.out Mon Jun 10 01:04:43 2013 +0100
145.3 @@ -1,1 +1,1 @@
145.4 -122
145.5 +122
146.1 --- a/tests/basic/ref-expr.sp Mon Jun 10 00:46:29 2013 +0100
146.2 +++ b/tests/basic/ref-expr.sp Mon Jun 10 01:04:43 2013 +0100
146.3 @@ -1,13 +1,13 @@
146.4 -native PrintNum(num);
146.5 -
146.6 -f(&a)
146.7 -{
146.8 - for (new i = 0; i < 10; i = i + 1)
146.9 - a = a + i;
146.10 - return a;
146.11 -}
146.12 -
146.13 -public main()
146.14 -{
146.15 - PrintNum(f(77));
146.16 -}
146.17 +native PrintNum(num);
146.18 +
146.19 +f(&a)
146.20 +{
146.21 + for (new i = 0; i < 10; i = i + 1)
146.22 + a = a + i;
146.23 + return a;
146.24 +}
146.25 +
146.26 +public main()
146.27 +{
146.28 + PrintNum(f(77));
146.29 +}
147.1 --- a/tests/basic/ref-var.out Mon Jun 10 00:46:29 2013 +0100
147.2 +++ b/tests/basic/ref-var.out Mon Jun 10 01:04:43 2013 +0100
147.3 @@ -1,1 +1,1 @@
147.4 -122
147.5 +122
148.1 --- a/tests/basic/ref-var.sp Mon Jun 10 00:46:29 2013 +0100
148.2 +++ b/tests/basic/ref-var.sp Mon Jun 10 01:04:43 2013 +0100
148.3 @@ -1,15 +1,15 @@
148.4 -native PrintNum(num);
148.5 -
148.6 -f(&a)
148.7 -{
148.8 - for (new i = 0; i < 10; i = i + 1)
148.9 - a = a + i;
148.10 - return 0;
148.11 -}
148.12 -
148.13 -public main()
148.14 -{
148.15 - new b = 77;
148.16 - f(b);
148.17 - PrintNum(b);
148.18 -}
148.19 +native PrintNum(num);
148.20 +
148.21 +f(&a)
148.22 +{
148.23 + for (new i = 0; i < 10; i = i + 1)
148.24 + a = a + i;
148.25 + return 0;
148.26 +}
148.27 +
148.28 +public main()
148.29 +{
148.30 + new b = 77;
148.31 + f(b);
148.32 + PrintNum(b);
148.33 +}
149.1 --- a/tests/basic/return-analyze-for-1.sp Mon Jun 10 00:46:29 2013 +0100
149.2 +++ b/tests/basic/return-analyze-for-1.sp Mon Jun 10 01:04:43 2013 +0100
149.3 @@ -1,12 +1,12 @@
149.4 -public f()
149.5 -{
149.6 - for (;;) {
149.7 - }
149.8 -}
149.9 -
149.10 -public main()
149.11 -{
149.12 -}
149.13 -
149.14 -
149.15 -
149.16 +public f()
149.17 +{
149.18 + for (;;) {
149.19 + }
149.20 +}
149.21 +
149.22 +public main()
149.23 +{
149.24 +}
149.25 +
149.26 +
149.27 +
150.1 --- a/tests/basic/return-analyze-for-2.out Mon Jun 10 00:46:29 2013 +0100
150.2 +++ b/tests/basic/return-analyze-for-2.out Mon Jun 10 01:04:43 2013 +0100
150.3 @@ -1,1 +1,1 @@
150.4 -5
150.5 +5
151.1 --- a/tests/basic/return-analyze-for-2.sp Mon Jun 10 00:46:29 2013 +0100
151.2 +++ b/tests/basic/return-analyze-for-2.sp Mon Jun 10 01:04:43 2013 +0100
151.3 @@ -1,16 +1,16 @@
151.4 -native PrintNum(num);
151.5 -
151.6 -f()
151.7 -{
151.8 - for (;;) {
151.9 - return 5;
151.10 - }
151.11 -}
151.12 -
151.13 -public main()
151.14 -{
151.15 - PrintNum(f());
151.16 -}
151.17 -
151.18 -
151.19 -
151.20 +native PrintNum(num);
151.21 +
151.22 +f()
151.23 +{
151.24 + for (;;) {
151.25 + return 5;
151.26 + }
151.27 +}
151.28 +
151.29 +public main()
151.30 +{
151.31 + PrintNum(f());
151.32 +}
151.33 +
151.34 +
151.35 +
152.1 --- a/tests/basic/return-analyze-for-3.err Mon Jun 10 00:46:29 2013 +0100
152.2 +++ b/tests/basic/return-analyze-for-3.err Mon Jun 10 01:04:43 2013 +0100
152.3 @@ -1,1 +1,1 @@
152.4 - line 1, col 2: not all paths through function return a value
152.5 + line 1, col 2: not all paths through function return a value
153.1 --- a/tests/basic/return-analyze-for-3.sp Mon Jun 10 00:46:29 2013 +0100
153.2 +++ b/tests/basic/return-analyze-for-3.sp Mon Jun 10 01:04:43 2013 +0100
153.3 @@ -1,13 +1,13 @@
153.4 -f(x)
153.5 -{
153.6 - for (;;) {
153.7 - if (x)
153.8 - return 5;
153.9 - }
153.10 -}
153.11 -
153.12 -public main()
153.13 -{
153.14 - f(5);
153.15 -}
153.16 -
153.17 +f(x)
153.18 +{
153.19 + for (;;) {
153.20 + if (x)
153.21 + return 5;
153.22 + }
153.23 +}
153.24 +
153.25 +public main()
153.26 +{
153.27 + f(5);
153.28 +}
153.29 +
154.1 --- a/tests/basic/return-analyze-for-4.err Mon Jun 10 00:46:29 2013 +0100
154.2 +++ b/tests/basic/return-analyze-for-4.err Mon Jun 10 01:04:43 2013 +0100
154.3 @@ -1,1 +1,1 @@
154.4 - line 1, col 8: not all paths through function return a value
154.5 + line 1, col 8: not all paths through function return a value
155.1 --- a/tests/basic/return-analyze-for-4.sp Mon Jun 10 00:46:29 2013 +0100
155.2 +++ b/tests/basic/return-analyze-for-4.sp Mon Jun 10 01:04:43 2013 +0100
155.3 @@ -1,13 +1,13 @@
155.4 -public f(x)
155.5 -{
155.6 - for (; x;) {
155.7 - return 5;
155.8 - }
155.9 -}
155.10 -
155.11 -public main()
155.12 -{
155.13 - return f(5);
155.14 -}
155.15 -
155.16 -
155.17 +public f(x)
155.18 +{
155.19 + for (; x;) {
155.20 + return 5;
155.21 + }
155.22 +}
155.23 +
155.24 +public main()
155.25 +{
155.26 + return f(5);
155.27 +}
155.28 +
155.29 +
156.1 --- a/tests/basic/return-analyze-for-5.out Mon Jun 10 00:46:29 2013 +0100
156.2 +++ b/tests/basic/return-analyze-for-5.out Mon Jun 10 01:04:43 2013 +0100
156.3 @@ -1,1 +1,1 @@
156.4 -54
156.5 +54
157.1 --- a/tests/basic/return-analyze-for-5.sp Mon Jun 10 00:46:29 2013 +0100
157.2 +++ b/tests/basic/return-analyze-for-5.sp Mon Jun 10 01:04:43 2013 +0100
157.3 @@ -1,17 +1,17 @@
157.4 -native PrintNum(num);
157.5 -
157.6 -f(x)
157.7 -{
157.8 - for (; x;) {
157.9 - return 5;
157.10 - }
157.11 - return 4;
157.12 -}
157.13 -
157.14 -public main()
157.15 -{
157.16 - PrintNum(f(5));
157.17 - PrintNum(f(0));
157.18 -}
157.19 -
157.20 -
157.21 +native PrintNum(num);
157.22 +
157.23 +f(x)
157.24 +{
157.25 + for (; x;) {
157.26 + return 5;
157.27 + }
157.28 + return 4;
157.29 +}
157.30 +
157.31 +public main()
157.32 +{
157.33 + PrintNum(f(5));
157.34 + PrintNum(f(0));
157.35 +}
157.36 +
157.37 +
158.1 --- a/tests/basic/return-analyze-if-1.out Mon Jun 10 00:46:29 2013 +0100
158.2 +++ b/tests/basic/return-analyze-if-1.out Mon Jun 10 01:04:43 2013 +0100
158.3 @@ -1,1 +1,1 @@
158.4 -25
158.5 +25
159.1 --- a/tests/basic/return-analyze-if-1.sp Mon Jun 10 00:46:29 2013 +0100
159.2 +++ b/tests/basic/return-analyze-if-1.sp Mon Jun 10 01:04:43 2013 +0100
159.3 @@ -1,16 +1,16 @@
159.4 -native PrintNum(num);
159.5 -
159.6 -f(x)
159.7 -{
159.8 - if (x)
159.9 - return 5;
159.10 - return 2;
159.11 -}
159.12 -
159.13 -public main()
159.14 -{
159.15 - PrintNum(f(0));
159.16 - PrintNum(f(1));
159.17 -}
159.18 -
159.19 -
159.20 +native PrintNum(num);
159.21 +
159.22 +f(x)
159.23 +{
159.24 + if (x)
159.25 + return 5;
159.26 + return 2;
159.27 +}
159.28 +
159.29 +public main()
159.30 +{
159.31 + PrintNum(f(0));
159.32 + PrintNum(f(1));
159.33 +}
159.34 +
159.35 +
160.1 --- a/tests/basic/return-analyze-if-2.err Mon Jun 10 00:46:29 2013 +0100
160.2 +++ b/tests/basic/return-analyze-if-2.err Mon Jun 10 01:04:43 2013 +0100
160.3 @@ -1,1 +1,1 @@
160.4 - line 3, col 3: not all paths through function return a value
160.5 + line 3, col 3: not all paths through function return a value
161.1 --- a/tests/basic/return-analyze-if-2.sp Mon Jun 10 00:46:29 2013 +0100
161.2 +++ b/tests/basic/return-analyze-if-2.sp Mon Jun 10 01:04:43 2013 +0100
161.3 @@ -1,14 +1,14 @@
161.4 -native PrintNum(num);
161.5 -
161.6 -f(x)
161.7 -{
161.8 - if (x)
161.9 - return 5;
161.10 -}
161.11 -
161.12 -public main()
161.13 -{
161.14 - PrintNum(f(4));
161.15 -}
161.16 -
161.17 -
161.18 +native PrintNum(num);
161.19 +
161.20 +f(x)
161.21 +{
161.22 + if (x)
161.23 + return 5;
161.24 +}
161.25 +
161.26 +public main()
161.27 +{
161.28 + PrintNum(f(4));
161.29 +}
161.30 +
161.31 +
162.1 --- a/tests/basic/return-analyze-if-3.out Mon Jun 10 00:46:29 2013 +0100
162.2 +++ b/tests/basic/return-analyze-if-3.out Mon Jun 10 01:04:43 2013 +0100
162.3 @@ -1,1 +1,1 @@
162.4 -65
162.5 +65
163.1 --- a/tests/basic/return-analyze-if-3.sp Mon Jun 10 00:46:29 2013 +0100
163.2 +++ b/tests/basic/return-analyze-if-3.sp Mon Jun 10 01:04:43 2013 +0100
163.3 @@ -1,17 +1,17 @@
163.4 -native PrintNum(num);
163.5 -
163.6 -f(x)
163.7 -{
163.8 - if (x)
163.9 - return 5;
163.10 - else
163.11 - return 6;
163.12 -}
163.13 -
163.14 -public main()
163.15 -{
163.16 - PrintNum(f(0));
163.17 - PrintNum(f(1));
163.18 -}
163.19 -
163.20 -
163.21 +native PrintNum(num);
163.22 +
163.23 +f(x)
163.24 +{
163.25 + if (x)
163.26 + return 5;
163.27 + else
163.28 + return 6;
163.29 +}
163.30 +
163.31 +public main()
163.32 +{
163.33 + PrintNum(f(0));
163.34 + PrintNum(f(1));
163.35 +}
163.36 +
163.37 +
164.1 --- a/tests/basic/return-analyze-if-4.err Mon Jun 10 00:46:29 2013 +0100
164.2 +++ b/tests/basic/return-analyze-if-4.err Mon Jun 10 01:04:43 2013 +0100
164.3 @@ -1,1 +1,1 @@
164.4 - line 3, col 3: not all paths through function return a value
164.5 + line 3, col 3: not all paths through function return a value
165.1 --- a/tests/basic/return-analyze-if-4.sp Mon Jun 10 00:46:29 2013 +0100
165.2 +++ b/tests/basic/return-analyze-if-4.sp Mon Jun 10 01:04:43 2013 +0100
165.3 @@ -1,17 +1,17 @@
165.4 -native PrintNum(num);
165.5 -
165.6 -f(x)
165.7 -{
165.8 - if (x)
165.9 - return 5;
165.10 - else if (x)
165.11 - return 6;
165.12 -}
165.13 -
165.14 -public main()
165.15 -{
165.16 - PrintNum(f(0));
165.17 - PrintNum(f(1));
165.18 -}
165.19 -
165.20 -
165.21 +native PrintNum(num);
165.22 +
165.23 +f(x)
165.24 +{
165.25 + if (x)
165.26 + return 5;
165.27 + else if (x)
165.28 + return 6;
165.29 +}
165.30 +
165.31 +public main()
165.32 +{
165.33 + PrintNum(f(0));
165.34 + PrintNum(f(1));
165.35 +}
165.36 +
165.37 +
166.1 --- a/tests/basic/return-analyze-if-5.out Mon Jun 10 00:46:29 2013 +0100
166.2 +++ b/tests/basic/return-analyze-if-5.out Mon Jun 10 01:04:43 2013 +0100
166.3 @@ -1,1 +1,1 @@
166.4 -596
166.5 +596
167.1 --- a/tests/basic/return-analyze-if-5.sp Mon Jun 10 00:46:29 2013 +0100
167.2 +++ b/tests/basic/return-analyze-if-5.sp Mon Jun 10 01:04:43 2013 +0100
167.3 @@ -1,20 +1,20 @@
167.4 -native PrintNum(num);
167.5 -
167.6 -f(x)
167.7 -{
167.8 - if (x == 5)
167.9 - return 5;
167.10 - else if (x == 7)
167.11 - return 9;
167.12 - else
167.13 - return 6;
167.14 -}
167.15 -
167.16 -public main()
167.17 -{
167.18 - PrintNum(f(5));
167.19 - PrintNum(f(7));
167.20 - PrintNum(f(2));
167.21 -}
167.22 -
167.23 -
167.24 +native PrintNum(num);
167.25 +
167.26 +f(x)
167.27 +{
167.28 + if (x == 5)
167.29 + return 5;
167.30 + else if (x == 7)
167.31 + return 9;
167.32 + else
167.33 + return 6;
167.34 +}
167.35 +
167.36 +public main()
167.37 +{
167.38 + PrintNum(f(5));
167.39 + PrintNum(f(7));
167.40 + PrintNum(f(2));
167.41 +}
167.42 +
167.43 +
168.1 --- a/tests/basic/shell.sp Mon Jun 10 00:46:29 2013 +0100
168.2 +++ b/tests/basic/shell.sp Mon Jun 10 01:04:43 2013 +0100
168.3 @@ -1,3 +1,3 @@
168.4 -native PrintNum(num);
168.5 -native PrintString(const char:text[]);
168.6 -native PrintFloat(float:f);
168.7 +native PrintNum(num);
168.8 +native PrintString(const char:text[]);
168.9 +native PrintFloat(float:f);
169.1 --- a/tests/basic/string-lit-1.out Mon Jun 10 00:46:29 2013 +0100
169.2 +++ b/tests/basic/string-lit-1.out Mon Jun 10 01:04:43 2013 +0100
169.3 @@ -1,1 +1,1 @@
169.4 -101121
169.5 +101121
170.1 --- a/tests/basic/string-lit-1.sp Mon Jun 10 00:46:29 2013 +0100
170.2 +++ b/tests/basic/string-lit-1.sp Mon Jun 10 01:04:43 2013 +0100
170.3 @@ -1,9 +1,9 @@
170.4 -native PrintNum(num);
170.5 -
170.6 -public main()
170.7 -{
170.8 - new char:str1[] = "hello";
170.9 - new char:str2[4] = "bye";
170.10 - PrintNum(str1[1]);
170.11 - PrintNum(str2[1]);
170.12 -}
170.13 +native PrintNum(num);
170.14 +
170.15 +public main()
170.16 +{
170.17 + new char:str1[] = "hello";
170.18 + new char:str2[4] = "bye";
170.19 + PrintNum(str1[1]);
170.20 + PrintNum(str2[1]);
170.21 +}
171.1 --- a/tests/basic/string-lit-2.out Mon Jun 10 00:46:29 2013 +0100
171.2 +++ b/tests/basic/string-lit-2.out Mon Jun 10 01:04:43 2013 +0100
171.3 @@ -1,1 +1,1 @@
171.4 -6568101121
171.5 +6568101121
172.1 --- a/tests/basic/string-lit-2.sp Mon Jun 10 00:46:29 2013 +0100
172.2 +++ b/tests/basic/string-lit-2.sp Mon Jun 10 01:04:43 2013 +0100
172.3 @@ -1,26 +1,26 @@
172.4 -native PrintNum(num);
172.5 -
172.6 -f(x)
172.7 -{
172.8 - new char:str1[];
172.9 - new char:str2[4];
172.10 -
172.11 - str1 = "hello";
172.12 - str2 = "bye";
172.13 -
172.14 - // Make sure modifying the string doesn't modify the
172.15 - // canonical literals.
172.16 - if (x) {
172.17 - str1[1] = 65;
172.18 - str2[1] = 68;
172.19 - }
172.20 -
172.21 - PrintNum(str1[1]);
172.22 - PrintNum(str2[1]);
172.23 -}
172.24 -
172.25 -public main()
172.26 -{
172.27 - f(1);
172.28 - f(0);
172.29 -}
172.30 +native PrintNum(num);
172.31 +
172.32 +f(x)
172.33 +{
172.34 + new char:str1[];
172.35 + new char:str2[4];
172.36 +
172.37 + str1 = "hello";
172.38 + str2 = "bye";
172.39 +
172.40 + // Make sure modifying the string doesn't modify the
172.41 + // canonical literals.
172.42 + if (x) {
172.43 + str1[1] = 65;
172.44 + str2[1] = 68;
172.45 + }
172.46 +
172.47 + PrintNum(str1[1]);
172.48 + PrintNum(str2[1]);
172.49 +}
172.50 +
172.51 +public main()
172.52 +{
172.53 + f(1);
172.54 + f(0);
172.55 +}
173.1 --- a/tests/basic/while.out Mon Jun 10 00:46:29 2013 +0100
173.2 +++ b/tests/basic/while.out Mon Jun 10 01:04:43 2013 +0100
173.3 @@ -1,1 +1,1 @@
173.4 -111
173.5 +111
174.1 --- a/tests/basic/while.sp Mon Jun 10 00:46:29 2013 +0100
174.2 +++ b/tests/basic/while.sp Mon Jun 10 01:04:43 2013 +0100
174.3 @@ -1,10 +1,10 @@
174.4 -native PrintNum(num);
174.5 -
174.6 -public main()
174.7 -{
174.8 - new i = 0;
174.9 - while (i < 100) {
174.10 - i = i + 37;
174.11 - }
174.12 - PrintNum(i);
174.13 -}
174.14 +native PrintNum(num);
174.15 +
174.16 +public main()
174.17 +{
174.18 + new i = 0;
174.19 + while (i < 100) {
174.20 + i = i + 37;
174.21 + }
174.22 + PrintNum(i);
174.23 +}
175.1 --- a/tests/display.py Mon Jun 10 00:46:29 2013 +0100
175.2 +++ b/tests/display.py Mon Jun 10 01:04:43 2013 +0100
175.3 @@ -1,23 +1,23 @@
175.4 -# vim: set ts=2 sw=2 tw=99 ft=python et:
175.5 -
175.6 -class Interactive:
175.7 - def __init__(self):
175.8 - self.failures = []
175.9 - self.timeouts = []
175.10 -
175.11 - def begin(self, tests):
175.12 - return
175.13 -
175.14 - def result(self, test, r):
175.15 - if r.ok:
175.16 - print('PASS: ' + test.name)
175.17 - else:
175.18 - if r.timeout:
175.19 - print('TIMEOUT: ' + test.name)
175.20 - else:
175.21 - print('FAIL: ' + test.name)
175.22 - print(' -- Error code: ' + str(r.code))
175.23 - print(' -- message: \n' + r.message)
175.24 - print(' -- stdout: \n' + r.out)
175.25 - print(' -- stderr: \n' + r.err)
175.26 -
175.27 +# vim: set ts=2 sw=2 tw=99 ft=python et:
175.28 +
175.29 +class Interactive:
175.30 + def __init__(self):
175.31 + self.failures = []
175.32 + self.timeouts = []
175.33 +
175.34 + def begin(self, tests):
175.35 + return
175.36 +
175.37 + def result(self, test, r):
175.38 + if r.ok:
175.39 + print('PASS: ' + test.name)
175.40 + else:
175.41 + if r.timeout:
175.42 + print('TIMEOUT: ' + test.name)
175.43 + else:
175.44 + print('FAIL: ' + test.name)
175.45 + print(' -- Error code: ' + str(r.code))
175.46 + print(' -- message: \n' + r.message)
175.47 + print(' -- stdout: \n' + r.out)
175.48 + print(' -- stderr: \n' + r.err)
175.49 +
176.1 --- a/tests/harness.py Mon Jun 10 00:46:29 2013 +0100
176.2 +++ b/tests/harness.py Mon Jun 10 01:04:43 2013 +0100
176.3 @@ -1,116 +1,116 @@
176.4 -# vim: set ts=2 sw=4 tw=99 ft=python et:
176.5 -import os
176.6 -import re
176.7 -import sys
176.8 -import time
176.9 -import os.path
176.10 -from test import Test
176.11 -from subprocess import *
176.12 -from threading import Thread
176.13 -from display import Interactive
176.14 -
176.15 -def FindTests(tests, root, folder):
176.16 - folders = []
176.17 - for name in os.listdir(os.path.join(root, folder)):
176.18 - path = os.path.join(root, folder, name)
176.19 - if os.path.isdir(path):
176.20 - folders.append(name)
176.21 - continue
176.22 -
176.23 - out = re.match("^([^\.]+)\.out$", name)
176.24 - err = re.match("^([^\.]+)\.err$", name)
176.25 - if out:
176.26 - name = os.path.join(folder, out.group(1))
176.27 - tests.append(Test(root, name, 'out'))
176.28 - elif err:
176.29 - name = os.path.join(folder, err.group(1))
176.30 - tests.append(Test(root, name, 'err'))
176.31 -
176.32 - for name in folders:
176.33 - path = os.path.join(folder, name)
176.34 - FindTests(tests, root, path)
176.35 -
176.36 -def IsTestRoot(path, name):
176.37 - return os.path.isdir(path)
176.38 -
176.39 -def RunTest_(argv, options, L):
176.40 - if sys.platform != 'win32':
176.41 - options['close_fds'] = True
176.42 -
176.43 - p = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
176.44 -
176.45 - L[0] = p
176.46 - out, err = p.communicate()
176.47 - L[1] = (out, err, p.returncode)
176.48 -
176.49 -def RunTest(test, options, shell):
176.50 - argv = [shell, test.cmd()]
176.51 -
176.52 - L = [None, None]
176.53 - timeout = False
176.54 - th = Thread(target = RunTest_, args = (argv, options, L))
176.55 - th.start()
176.56 - th.join(10.0)
176.57 - while th.isAlive():
176.58 - if L[0] is not None:
176.59 - try:
176.60 - L[0].kill()
176.61 - time.sleep(.1)
176.62 - timeout = True
176.63 - except e:
176.64 - pass
176.65 -
176.66 - th.join()
176.67 - (out, err, code) = L[1]
176.68 -
176.69 - return test.check(out, err, code, timeout)
176.70 -
176.71 -def RunTests(display, tests, shell):
176.72 - display.begin(tests)
176.73 - ok = True
176.74 - try:
176.75 - for test in tests:
176.76 - options = { }
176.77 - result = RunTest(test, options, shell)
176.78 -
176.79 - ok = ok and result.ok
176.80 -
176.81 - display.result(test, result)
176.82 - except KeyboardInterrupt:
176.83 - display.cancel()
176.84 - ok = False
176.85 -
176.86 - return ok
176.87 -
176.88 -
176.89 -def main(argv):
176.90 - root = os.path.dirname(os.path.abspath(__file__))
176.91 -
176.92 - from optparse import OptionParser
176.93 - op = OptionParser(usage='%prog [options] <shell>')
176.94 - (options, args) = op.parse_args(argv)
176.95 -
176.96 - if len(args) != 1:
176.97 - op.error('missing <shell> argument')
176.98 -
176.99 - shell = os.path.normpath(args[0])
176.100 -
176.101 - tests = []
176.102 - for name in os.listdir(root):
176.103 - path = os.path.join(root, name)
176.104 - if IsTestRoot(path, name):
176.105 - FindTests(tests, root, name)
176.106 -
176.107 - if len(tests) == 0:
176.108 - op.error('no test cases found')
176.109 -
176.110 - display = Interactive()
176.111 - ok = RunTests(display, tests, shell)
176.112 - if ok:
176.113 - sys.exit(0)
176.114 - else:
176.115 - sys.exit(1)
176.116 -
176.117 -if __name__ == '__main__':
176.118 - main(sys.argv[1:])
176.119 -
176.120 +# vim: set ts=2 sw=4 tw=99 ft=python et:
176.121 +import os
176.122 +import re
176.123 +import sys
176.124 +import time
176.125 +import os.path
176.126 +from test import Test
176.127 +from subprocess import *
176.128 +from threading import Thread
176.129 +from display import Interactive
176.130 +
176.131 +def FindTests(tests, root, folder):
176.132 + folders = []
176.133 + for name in os.listdir(os.path.join(root, folder)):
176.134 + path = os.path.join(root, folder, name)
176.135 + if os.path.isdir(path):
176.136 + folders.append(name)
176.137 + continue
176.138 +
176.139 + out = re.match("^([^\.]+)\.out$", name)
176.140 + err = re.match("^([^\.]+)\.err$", name)
176.141 + if out:
176.142 + name = os.path.join(folder, out.group(1))
176.143 + tests.append(Test(root, name, 'out'))
176.144 + elif err:
176.145 + name = os.path.join(folder, err.group(1))
176.146 + tests.append(Test(root, name, 'err'))
176.147 +
176.148 + for name in folders:
176.149 + path = os.path.join(folder, name)
176.150 + FindTests(tests, root, path)
176.151 +
176.152 +def IsTestRoot(path, name):
176.153 + return os.path.isdir(path)
176.154 +
176.155 +def RunTest_(argv, options, L):
176.156 + if sys.platform != 'win32':
176.157 + options['close_fds'] = True
176.158 +
176.159 + p = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE, **options)
176.160 +
176.161 + L[0] = p
176.162 + out, err = p.communicate()
176.163 + L[1] = (out, err, p.returncode)
176.164 +
176.165 +def RunTest(test, options, shell):
176.166 + argv = [shell, test.cmd()]
176.167 +
176.168 + L = [None, None]
176.169 + timeout = False
176.170 + th = Thread(target = RunTest_, args = (argv, options, L))
176.171 + th.start()
176.172 + th.join(10.0)
176.173 + while th.isAlive():
176.174 + if L[0] is not None:
176.175 + try:
176.176 + L[0].kill()
176.177 + time.sleep(.1)
176.178 + timeout = True
176.179 + except e:
176.180 + pass
176.181 +
176.182 + th.join()
176.183 + (out, err, code) = L[1]
176.184 +
176.185 + return test.check(out, err, code, timeout)
176.186 +
176.187 +def RunTests(display, tests, shell):
176.188 + display.begin(tests)
176.189 + ok = True
176.190 + try:
176.191 + for test in tests:
176.192 + options = { }
176.193 + result = RunTest(test, options, shell)
176.194 +
176.195 + ok = ok and result.ok
176.196 +
176.197 + display.result(test, result)
176.198 + except KeyboardInterrupt:
176.199 + display.cancel()
176.200 + ok = False
176.201 +
176.202 + return ok
176.203 +
176.204 +
176.205 +def main(argv):
176.206 + root = os.path.dirname(os.path.abspath(__file__))
176.207 +
176.208 + from optparse import OptionParser
176.209 + op = OptionParser(usage='%prog [options] <shell>')
176.210 + (options, args) = op.parse_args(argv)
176.211 +
176.212 + if len(args) != 1:
176.213 + op.error('missing <shell> argument')
176.214 +
176.215 + shell = os.path.normpath(args[0])
176.216 +
176.217 + tests = []
176.218 + for name in os.listdir(root):
176.219 + path = os.path.join(root, name)
176.220 + if IsTestRoot(path, name):
176.221 + FindTests(tests, root, name)
176.222 +
176.223 + if len(tests) == 0:
176.224 + op.error('no test cases found')
176.225 +
176.226 + display = Interactive()
176.227 + ok = RunTests(display, tests, shell)
176.228 + if ok:
176.229 + sys.exit(0)
176.230 + else:
176.231 + sys.exit(1)
176.232 +
176.233 +if __name__ == '__main__':
176.234 + main(sys.argv[1:])
176.235 +
177.1 --- a/tests/prototype/string-1.sp Mon Jun 10 00:46:29 2013 +0100
177.2 +++ b/tests/prototype/string-1.sp Mon Jun 10 01:04:43 2013 +0100
177.3 @@ -1,6 +1,6 @@
177.4 -main()
177.5 -{
177.6 - new String:buffer[100] = "clam";
177.7 - buffer = "hedgehog";
177.8 - return buffer[3];
177.9 -}
177.10 +main()
177.11 +{
177.12 + new String:buffer[100] = "clam";
177.13 + buffer = "hedgehog";
177.14 + return buffer[3];
177.15 +}
178.1 --- a/tests/ref-array.sp Mon Jun 10 00:46:29 2013 +0100
178.2 +++ b/tests/ref-array.sp Mon Jun 10 01:04:43 2013 +0100
178.3 @@ -1,13 +1,13 @@
178.4 -f(&a)
178.5 -{
178.6 - for (new i = 0; i < 10; i = i + 1)
178.7 - a = a + i;
178.8 - return a;
178.9 -}
178.10 -
178.11 -main()
178.12 -{
178.13 - new array[4];
178.14 - f(array[3]);
178.15 - return array[3];
178.16 -}
178.17 +f(&a)
178.18 +{
178.19 + for (new i = 0; i < 10; i = i + 1)
178.20 + a = a + i;
178.21 + return a;
178.22 +}
178.23 +
178.24 +main()
178.25 +{
178.26 + new array[4];
178.27 + f(array[3]);
178.28 + return array[3];
178.29 +}
179.1 --- a/tests/test.py Mon Jun 10 00:46:29 2013 +0100
179.2 +++ b/tests/test.py Mon Jun 10 01:04:43 2013 +0100
179.3 @@ -1,64 +1,64 @@
179.4 -# vim: set ts=2 sw=4 tw=99 ft=python et:
179.5 -import os
179.6 -import os.path
179.7 -
179.8 -class Result:
179.9 - def __init__(self, ok, out, err, code, timeout, message):
179.10 - self.ok = ok
179.11 - self.out = out
179.12 - self.err = err
179.13 - self.code = code
179.14 - self.timeout = timeout
179.15 - self.message = message
179.16 -
179.17 -class Test:
179.18 - def __init__(self, path, name, type):
179.19 - self.path = path
179.20 - self.name = name
179.21 - self.type = type
179.22 -
179.23 - def cmd(self):
179.24 - return os.path.join(self.path, self.name + '.sp')
179.25 -
179.26 - def compare(self, text):
179.27 - ok = True
179.28 - message = None
179.29 - with open(os.path.join(self.path, self.name + '.' + self.type), 'rt') as f:
179.30 - text = str.replace(text, '\r', '')
179.31 - lines = text.split('\n')
179.32 - i = 0
179.33 - for line in f:
179.34 - line = line.rstrip('\r\n')
179.35 - if "Displaying compilation errors for" in lines[i]:
179.36 - i += 1
179.37 - continue
179.38 - if line != lines[i]:
179.39 - message = 'Got "' + lines[i] + '", expected "' + line + '"'
179.40 - ok = False
179.41 - break
179.42 - i += 1
179.43 - return (ok, message)
179.44 -
179.45 - def check(self, out, err, code, timeout):
179.46 - if not out:
179.47 - out = ''
179.48 - if not err:
179.49 - err = ''
179.50 - if self.type == 'err':
179.51 - if code == 0:
179.52 - message = 'Expected failure, got success'
179.53 - ok = False
179.54 - else:
179.55 - (ok, message) = self.compare(err)
179.56 - elif self.type == 'out':
179.57 - if code != 0:
179.58 - message = 'Expected success, got failure (code: ' + str(code) + ')'
179.59 - ok = False
179.60 - else:
179.61 - (ok, message) = self.compare(out)
179.62 -
179.63 - if timeout:
179.64 - ok = False
179.65 - message = 'timeout'
179.66 -
179.67 - return Result(ok, out, err, code, timeout, message)
179.68 +# vim: set ts=2 sw=4 tw=99 ft=python et:
179.69 +import os
179.70 +import os.path
179.71 +
179.72 +class Result:
179.73 + def __init__(self, ok, out, err, code, timeout, message):
179.74 + self.ok = ok
179.75 + self.out = out
179.76 + self.err = err
179.77 + self.code = code
179.78 + self.timeout = timeout
179.79 + self.message = message
179.80 +
179.81 +class Test:
179.82 + def __init__(self, path, name, type):
179.83 + self.path = path
179.84 + self.name = name
179.85 + self.type = type
179.86 +
179.87 + def cmd(self):
179.88 + return os.path.join(self.path, self.name + '.sp')
179.89 +
179.90 + def compare(self, text):
179.91 + ok = True
179.92 + message = None
179.93 + with open(os.path.join(self.path, self.name + '.' + self.type), 'rt') as f:
179.94 + text = str.replace(text, '\r', '')
179.95 + lines = text.split('\n')
179.96 + i = 0
179.97 + for line in f:
179.98 + line = line.rstrip('\r\n')
179.99 + if "Displaying compilation errors for" in lines[i]:
179.100 + i += 1
179.101 + continue
179.102 + if line != lines[i]:
179.103 + message = 'Got "' + lines[i] + '", expected "' + line + '"'
179.104 + ok = False
179.105 + break
179.106 + i += 1
179.107 + return (ok, message)
179.108 +
179.109 + def check(self, out, err, code, timeout):
179.110 + if not out:
179.111 + out = ''
179.112 + if not err:
179.113 + err = ''
179.114 + if self.type == 'err':
179.115 + if code == 0:
179.116 + message = 'Expected failure, got success'
179.117 + ok = False
179.118 + else:
179.119 + (ok, message) = self.compare(err)
179.120 + elif self.type == 'out':
179.121 + if code != 0:
179.122 + message = 'Expected success, got failure (code: ' + str(code) + ')'
179.123 + ok = False
179.124 + else:
179.125 + (ok, message) = self.compare(out)
179.126 +
179.127 + if timeout:
179.128 + ok = False
179.129 + message = 'timeout'
179.130 +
179.131 + return Result(ok, out, err, code, timeout, message)