New try: Parser: Delay internalizing strings and values
This is a reincarnation of r21841. The previous try was https://codereview.chromium.org/314603004/ but it regressed JSBench and morejs. BUG= R=rossberg@chromium.org Review URL: https://codereview.chromium.org/335293004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21972 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
256d406c73
commit
62ffc7de20
2
BUILD.gn
2
BUILD.gn
@ -447,6 +447,8 @@ source_set("v8_base") {
|
||||
"src/assembler.h",
|
||||
"src/assert-scope.h",
|
||||
"src/assert-scope.cc",
|
||||
"src/ast-value-factory.cc",
|
||||
"src/ast-value-factory.h",
|
||||
"src/ast.cc",
|
||||
"src/ast.h",
|
||||
"src/bignum-dtoa.cc",
|
||||
|
@ -5586,7 +5586,7 @@ class Internals {
|
||||
static const int kNullValueRootIndex = 7;
|
||||
static const int kTrueValueRootIndex = 8;
|
||||
static const int kFalseValueRootIndex = 9;
|
||||
static const int kEmptyStringRootIndex = 163;
|
||||
static const int kEmptyStringRootIndex = 160;
|
||||
|
||||
// The external allocation limit should be below 256 MB on all architectures
|
||||
// to avoid that resource-constrained embedders run low on memory.
|
||||
|
409
src/ast-value-factory.cc
Normal file
409
src/ast-value-factory.cc
Normal file
@ -0,0 +1,409 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "src/ast-value-factory.h"
|
||||
|
||||
#include "src/api.h"
|
||||
#include "src/objects.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
// For using StringToArrayIndex.
|
||||
class OneByteStringStream {
|
||||
public:
|
||||
explicit OneByteStringStream(Vector<const byte> lb) :
|
||||
literal_bytes_(lb), pos_(0) {}
|
||||
|
||||
bool HasMore() { return pos_ < literal_bytes_.length(); }
|
||||
uint16_t GetNext() { return literal_bytes_[pos_++]; }
|
||||
|
||||
private:
|
||||
Vector<const byte> literal_bytes_;
|
||||
int pos_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class AstRawStringInternalizationKey : public HashTableKey {
|
||||
public:
|
||||
explicit AstRawStringInternalizationKey(const AstRawString* string)
|
||||
: string_(string) {}
|
||||
|
||||
virtual bool IsMatch(Object* other) V8_OVERRIDE {
|
||||
if (string_->is_one_byte_)
|
||||
return String::cast(other)->IsOneByteEqualTo(string_->literal_bytes_);
|
||||
return String::cast(other)->IsTwoByteEqualTo(
|
||||
Vector<const uint16_t>::cast(string_->literal_bytes_));
|
||||
}
|
||||
|
||||
virtual uint32_t Hash() V8_OVERRIDE {
|
||||
return string_->hash() >> Name::kHashShift;
|
||||
}
|
||||
|
||||
virtual uint32_t HashForObject(Object* key) V8_OVERRIDE {
|
||||
return String::cast(key)->Hash();
|
||||
}
|
||||
|
||||
virtual Handle<Object> AsHandle(Isolate* isolate) V8_OVERRIDE {
|
||||
if (string_->is_one_byte_)
|
||||
return isolate->factory()->NewOneByteInternalizedString(
|
||||
string_->literal_bytes_, string_->hash());
|
||||
return isolate->factory()->NewTwoByteInternalizedString(
|
||||
Vector<const uint16_t>::cast(string_->literal_bytes_), string_->hash());
|
||||
}
|
||||
|
||||
private:
|
||||
const AstRawString* string_;
|
||||
};
|
||||
|
||||
|
||||
void AstRawString::Internalize(Isolate* isolate) {
|
||||
if (!string_.is_null()) return;
|
||||
if (literal_bytes_.length() == 0) {
|
||||
string_ = isolate->factory()->empty_string();
|
||||
} else {
|
||||
AstRawStringInternalizationKey key(this);
|
||||
string_ = StringTable::LookupKey(isolate, &key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AstRawString::AsArrayIndex(uint32_t* index) const {
|
||||
if (!string_.is_null())
|
||||
return string_->AsArrayIndex(index);
|
||||
if (!is_one_byte_ || literal_bytes_.length() == 0 ||
|
||||
literal_bytes_.length() > String::kMaxArrayIndexSize)
|
||||
return false;
|
||||
OneByteStringStream stream(literal_bytes_);
|
||||
return StringToArrayIndex(&stream, index);
|
||||
}
|
||||
|
||||
|
||||
bool AstRawString::IsOneByteEqualTo(const char* data) const {
|
||||
int length = static_cast<int>(strlen(data));
|
||||
if (is_one_byte_ && literal_bytes_.length() == length) {
|
||||
const char* token = reinterpret_cast<const char*>(literal_bytes_.start());
|
||||
return !strncmp(token, data, length);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AstRawString::Compare(void* a, void* b) {
|
||||
AstRawString* string1 = reinterpret_cast<AstRawString*>(a);
|
||||
AstRawString* string2 = reinterpret_cast<AstRawString*>(b);
|
||||
if (string1->is_one_byte_ != string2->is_one_byte_) return false;
|
||||
if (string1->hash_ != string2->hash_) return false;
|
||||
int length = string1->literal_bytes_.length();
|
||||
if (string2->literal_bytes_.length() != length) return false;
|
||||
return memcmp(string1->literal_bytes_.start(),
|
||||
string2->literal_bytes_.start(), length) == 0;
|
||||
}
|
||||
|
||||
|
||||
void AstConsString::Internalize(Isolate* isolate) {
|
||||
// AstRawStrings are internalized before AstConsStrings so left and right are
|
||||
// already internalized.
|
||||
string_ = isolate->factory()
|
||||
->NewConsString(left_->string(), right_->string())
|
||||
.ToHandleChecked();
|
||||
}
|
||||
|
||||
|
||||
bool AstValue::IsPropertyName() const {
|
||||
if (type_ == STRING) {
|
||||
uint32_t index;
|
||||
return !string_->AsArrayIndex(&index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AstValue::BooleanValue() const {
|
||||
switch (type_) {
|
||||
case STRING:
|
||||
ASSERT(string_ != NULL);
|
||||
return !string_->IsEmpty();
|
||||
case SYMBOL:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case NUMBER:
|
||||
return DoubleToBoolean(number_);
|
||||
case SMI:
|
||||
return smi_ != 0;
|
||||
case STRING_ARRAY:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case BOOLEAN:
|
||||
return bool_;
|
||||
case NULL_TYPE:
|
||||
return false;
|
||||
case THE_HOLE:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case UNDEFINED:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void AstValue::Internalize(Isolate* isolate) {
|
||||
switch (type_) {
|
||||
case STRING:
|
||||
ASSERT(string_ != NULL);
|
||||
// Strings are already internalized.
|
||||
ASSERT(!string_->string().is_null());
|
||||
break;
|
||||
case SYMBOL:
|
||||
value_ = Object::GetProperty(
|
||||
isolate, handle(isolate->native_context()->builtins()),
|
||||
symbol_name_).ToHandleChecked();
|
||||
break;
|
||||
case NUMBER:
|
||||
value_ = isolate->factory()->NewNumber(number_, TENURED);
|
||||
break;
|
||||
case SMI:
|
||||
value_ = handle(Smi::FromInt(smi_), isolate);
|
||||
break;
|
||||
case BOOLEAN:
|
||||
if (bool_) {
|
||||
value_ = isolate->factory()->true_value();
|
||||
} else {
|
||||
value_ = isolate->factory()->false_value();
|
||||
}
|
||||
break;
|
||||
case STRING_ARRAY: {
|
||||
ASSERT(strings_ != NULL);
|
||||
Factory* factory = isolate->factory();
|
||||
int len = strings_->length();
|
||||
Handle<FixedArray> elements = factory->NewFixedArray(len, TENURED);
|
||||
for (int i = 0; i < len; i++) {
|
||||
const AstRawString* string = (*strings_)[i];
|
||||
Handle<Object> element = string->string();
|
||||
// Strings are already internalized.
|
||||
ASSERT(!element.is_null());
|
||||
elements->set(i, *element);
|
||||
}
|
||||
value_ =
|
||||
factory->NewJSArrayWithElements(elements, FAST_ELEMENTS, TENURED);
|
||||
break;
|
||||
}
|
||||
case NULL_TYPE:
|
||||
value_ = isolate->factory()->null_value();
|
||||
break;
|
||||
case THE_HOLE:
|
||||
value_ = isolate->factory()->the_hole_value();
|
||||
break;
|
||||
case UNDEFINED:
|
||||
value_ = isolate->factory()->undefined_value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const AstRawString* AstValueFactory::GetOneByteString(
|
||||
Vector<const uint8_t> literal) {
|
||||
uint32_t hash = StringHasher::HashSequentialString<uint8_t>(
|
||||
literal.start(), literal.length(), hash_seed_);
|
||||
return GetString(hash, true, literal);
|
||||
}
|
||||
|
||||
|
||||
const AstRawString* AstValueFactory::GetTwoByteString(
|
||||
Vector<const uint16_t> literal) {
|
||||
uint32_t hash = StringHasher::HashSequentialString<uint16_t>(
|
||||
literal.start(), literal.length(), hash_seed_);
|
||||
return GetString(hash, false, Vector<const byte>::cast(literal));
|
||||
}
|
||||
|
||||
|
||||
const AstRawString* AstValueFactory::GetString(Handle<String> literal) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
String::FlatContent content = literal->GetFlatContent();
|
||||
if (content.IsAscii()) {
|
||||
return GetOneByteString(content.ToOneByteVector());
|
||||
}
|
||||
ASSERT(content.IsTwoByte());
|
||||
return GetTwoByteString(content.ToUC16Vector());
|
||||
}
|
||||
|
||||
|
||||
const AstConsString* AstValueFactory::NewConsString(
|
||||
const AstString* left, const AstString* right) {
|
||||
// This Vector will be valid as long as the Collector is alive (meaning that
|
||||
// the AstRawString will not be moved).
|
||||
AstConsString* new_string = new (zone_) AstConsString(left, right);
|
||||
strings_.Add(new_string);
|
||||
if (isolate_) {
|
||||
new_string->Internalize(isolate_);
|
||||
}
|
||||
return new_string;
|
||||
}
|
||||
|
||||
|
||||
void AstValueFactory::Internalize(Isolate* isolate) {
|
||||
if (isolate_) {
|
||||
// Everything is already internalized.
|
||||
return;
|
||||
}
|
||||
// Strings need to be internalized before values, because values refer to
|
||||
// strings.
|
||||
for (int i = 0; i < strings_.length(); ++i) {
|
||||
strings_[i]->Internalize(isolate);
|
||||
}
|
||||
for (int i = 0; i < values_.length(); ++i) {
|
||||
values_[i]->Internalize(isolate);
|
||||
}
|
||||
isolate_ = isolate;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewString(const AstRawString* string) {
|
||||
AstValue* value = new (zone_) AstValue(string);
|
||||
ASSERT(string != NULL);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewSymbol(const char* name) {
|
||||
AstValue* value = new (zone_) AstValue(name);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewNumber(double number) {
|
||||
AstValue* value = new (zone_) AstValue(number);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewSmi(int number) {
|
||||
AstValue* value =
|
||||
new (zone_) AstValue(AstValue::SMI, number);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewBoolean(bool b) {
|
||||
AstValue* value = new (zone_) AstValue(b);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewStringList(
|
||||
ZoneList<const AstRawString*>* strings) {
|
||||
AstValue* value = new (zone_) AstValue(strings);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewNull() {
|
||||
AstValue* value = new (zone_) AstValue(AstValue::NULL_TYPE);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewUndefined() {
|
||||
AstValue* value = new (zone_) AstValue(AstValue::UNDEFINED);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstValue* AstValueFactory::NewTheHole() {
|
||||
AstValue* value = new (zone_) AstValue(AstValue::THE_HOLE);
|
||||
if (isolate_) {
|
||||
value->Internalize(isolate_);
|
||||
}
|
||||
values_.Add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
const AstRawString* AstValueFactory::GetString(
|
||||
uint32_t hash, bool is_one_byte, Vector<const byte> literal_bytes) {
|
||||
// literal_bytes here points to whatever the user passed, and this is OK
|
||||
// because we use vector_compare (which checks the contents) to compare
|
||||
// against the AstRawStrings which are in the string_table_. We should not
|
||||
// return this AstRawString.
|
||||
AstRawString key(is_one_byte, literal_bytes, hash);
|
||||
HashMap::Entry* entry = string_table_.Lookup(&key, hash, true);
|
||||
if (entry->value == NULL) {
|
||||
// Copy literal contents for later comparison.
|
||||
int length = literal_bytes.length();
|
||||
byte* new_literal_bytes = zone_->NewArray<byte>(length);
|
||||
memcpy(new_literal_bytes, literal_bytes.start(), length);
|
||||
AstRawString* new_string = new (zone_) AstRawString(
|
||||
is_one_byte, Vector<const byte>(new_literal_bytes, length), hash);
|
||||
entry->key = new_string;
|
||||
strings_.Add(new_string);
|
||||
if (isolate_) {
|
||||
new_string->Internalize(isolate_);
|
||||
}
|
||||
entry->value = reinterpret_cast<void*>(1);
|
||||
}
|
||||
return reinterpret_cast<AstRawString*>(entry->key);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
340
src/ast-value-factory.h
Normal file
340
src/ast-value-factory.h
Normal file
@ -0,0 +1,340 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef V8_AST_VALUE_FACTORY_H_
|
||||
#define V8_AST_VALUE_FACTORY_H_
|
||||
|
||||
#include "src/api.h"
|
||||
#include "src/hashmap.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
// AstString, AstValue and AstValueFactory are for storing strings and values
|
||||
// independent of the V8 heap and internalizing them later. During parsing,
|
||||
// AstStrings and AstValues are created and stored outside the heap, in
|
||||
// AstValueFactory. After parsing, the strings and values are internalized
|
||||
// (moved into the V8 heap).
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class AstString : public ZoneObject {
|
||||
public:
|
||||
virtual ~AstString() {}
|
||||
|
||||
virtual int length() const = 0;
|
||||
bool IsEmpty() const { return length() == 0; }
|
||||
|
||||
// Puts the string into the V8 heap.
|
||||
virtual void Internalize(Isolate* isolate) = 0;
|
||||
|
||||
// This function can be called after internalizing.
|
||||
V8_INLINE Handle<String> string() const {
|
||||
ASSERT(!string_.is_null());
|
||||
return string_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// This is null until the string is internalized.
|
||||
Handle<String> string_;
|
||||
};
|
||||
|
||||
|
||||
class AstRawString : public AstString {
|
||||
public:
|
||||
virtual int length() const V8_OVERRIDE {
|
||||
if (is_one_byte_)
|
||||
return literal_bytes_.length();
|
||||
return literal_bytes_.length() / 2;
|
||||
}
|
||||
|
||||
virtual void Internalize(Isolate* isolate) V8_OVERRIDE;
|
||||
|
||||
bool AsArrayIndex(uint32_t* index) const;
|
||||
|
||||
// The string is not null-terminated, use length() to find out the length.
|
||||
const unsigned char* raw_data() const {
|
||||
return literal_bytes_.start();
|
||||
}
|
||||
bool is_one_byte() const { return is_one_byte_; }
|
||||
bool IsOneByteEqualTo(const char* data) const;
|
||||
uint16_t FirstCharacter() const {
|
||||
if (is_one_byte_)
|
||||
return literal_bytes_[0];
|
||||
const uint16_t* c =
|
||||
reinterpret_cast<const uint16_t*>(literal_bytes_.start());
|
||||
return *c;
|
||||
}
|
||||
|
||||
// For storing AstRawStrings in a hash map.
|
||||
uint32_t hash() const {
|
||||
return hash_;
|
||||
}
|
||||
static bool Compare(void* a, void* b);
|
||||
|
||||
private:
|
||||
friend class AstValueFactory;
|
||||
friend class AstRawStringInternalizationKey;
|
||||
|
||||
AstRawString(bool is_one_byte, const Vector<const byte>& literal_bytes,
|
||||
uint32_t hash)
|
||||
: is_one_byte_(is_one_byte), literal_bytes_(literal_bytes), hash_(hash) {}
|
||||
|
||||
AstRawString()
|
||||
: is_one_byte_(true),
|
||||
hash_(0) {}
|
||||
|
||||
bool is_one_byte_;
|
||||
|
||||
// Points to memory owned by Zone.
|
||||
Vector<const byte> literal_bytes_;
|
||||
uint32_t hash_;
|
||||
};
|
||||
|
||||
|
||||
class AstConsString : public AstString {
|
||||
public:
|
||||
AstConsString(const AstString* left, const AstString* right)
|
||||
: left_(left),
|
||||
right_(right) {}
|
||||
|
||||
virtual int length() const V8_OVERRIDE {
|
||||
return left_->length() + right_->length();
|
||||
}
|
||||
|
||||
virtual void Internalize(Isolate* isolate) V8_OVERRIDE;
|
||||
|
||||
private:
|
||||
friend class AstValueFactory;
|
||||
|
||||
const AstString* left_;
|
||||
const AstString* right_;
|
||||
};
|
||||
|
||||
|
||||
// AstValue is either a string, a number, a string array, a boolean, or a
|
||||
// special value (null, undefined, the hole).
|
||||
class AstValue : public ZoneObject {
|
||||
public:
|
||||
bool IsString() const {
|
||||
return type_ == STRING;
|
||||
}
|
||||
|
||||
bool IsNumber() const {
|
||||
return type_ == NUMBER || type_ == SMI;
|
||||
}
|
||||
|
||||
const AstRawString* AsString() const {
|
||||
if (type_ == STRING)
|
||||
return string_;
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
double AsNumber() const {
|
||||
if (type_ == NUMBER)
|
||||
return number_;
|
||||
if (type_ == SMI)
|
||||
return smi_;
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool EqualsString(const AstRawString* string) const {
|
||||
return type_ == STRING && string_ == string;
|
||||
}
|
||||
|
||||
bool IsPropertyName() const;
|
||||
|
||||
bool BooleanValue() const;
|
||||
|
||||
void Internalize(Isolate* isolate);
|
||||
|
||||
// Can be called after Internalize has been called.
|
||||
V8_INLINE Handle<Object> value() const {
|
||||
if (type_ == STRING) {
|
||||
return string_->string();
|
||||
}
|
||||
ASSERT(!value_.is_null());
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class AstValueFactory;
|
||||
|
||||
enum Type {
|
||||
STRING,
|
||||
SYMBOL,
|
||||
NUMBER,
|
||||
SMI,
|
||||
BOOLEAN,
|
||||
STRING_ARRAY,
|
||||
NULL_TYPE,
|
||||
UNDEFINED,
|
||||
THE_HOLE
|
||||
};
|
||||
|
||||
explicit AstValue(const AstRawString* s) : type_(STRING) { string_ = s; }
|
||||
|
||||
explicit AstValue(const char* name) : type_(SYMBOL) { symbol_name_ = name; }
|
||||
|
||||
explicit AstValue(double n) : type_(NUMBER) { number_ = n; }
|
||||
|
||||
AstValue(Type t, int i) : type_(t) {
|
||||
ASSERT(type_ == SMI);
|
||||
smi_ = i;
|
||||
}
|
||||
|
||||
explicit AstValue(bool b) : type_(BOOLEAN) { bool_ = b; }
|
||||
|
||||
explicit AstValue(ZoneList<const AstRawString*>* s) : type_(STRING_ARRAY) {
|
||||
strings_ = s;
|
||||
}
|
||||
|
||||
explicit AstValue(Type t) : type_(t) {
|
||||
ASSERT(t == NULL_TYPE || t == UNDEFINED || t == THE_HOLE);
|
||||
}
|
||||
|
||||
Type type_;
|
||||
|
||||
// Uninternalized value.
|
||||
union {
|
||||
const AstRawString* string_;
|
||||
double number_;
|
||||
int smi_;
|
||||
bool bool_;
|
||||
ZoneList<const AstRawString*>* strings_;
|
||||
const char* symbol_name_;
|
||||
};
|
||||
|
||||
// Internalized value (empty before internalized).
|
||||
Handle<Object> value_;
|
||||
};
|
||||
|
||||
|
||||
// For generating string constants.
|
||||
#define STRING_CONSTANTS(F) \
|
||||
F(anonymous_function, "(anonymous function)") \
|
||||
F(arguments, "arguments") \
|
||||
F(done, "done") \
|
||||
F(dot, ".") \
|
||||
F(dot_for, ".for") \
|
||||
F(dot_generator, ".generator") \
|
||||
F(dot_generator_object, ".generator_object") \
|
||||
F(dot_iterable, ".iterable") \
|
||||
F(dot_iterator, ".iterator") \
|
||||
F(dot_module, ".module") \
|
||||
F(dot_result, ".result") \
|
||||
F(empty, "") \
|
||||
F(eval, "eval") \
|
||||
F(initialize_const_global, "initializeConstGlobal") \
|
||||
F(initialize_var_global, "initializeVarGlobal") \
|
||||
F(make_reference_error, "MakeReferenceError") \
|
||||
F(make_syntax_error, "MakeSyntaxError") \
|
||||
F(make_type_error, "MakeTypeError") \
|
||||
F(module, "module") \
|
||||
F(native, "native") \
|
||||
F(next, "next") \
|
||||
F(proto, "__proto__") \
|
||||
F(prototype, "prototype") \
|
||||
F(this, "this") \
|
||||
F(use_strict, "use strict") \
|
||||
F(value, "value")
|
||||
|
||||
|
||||
class AstValueFactory {
|
||||
public:
|
||||
AstValueFactory(Zone* zone, uint32_t hash_seed)
|
||||
: string_table_(AstRawString::Compare),
|
||||
zone_(zone),
|
||||
isolate_(NULL),
|
||||
hash_seed_(hash_seed) {
|
||||
#define F(name, str) \
|
||||
name##_string_ = NULL;
|
||||
STRING_CONSTANTS(F)
|
||||
#undef F
|
||||
}
|
||||
|
||||
const AstRawString* GetOneByteString(Vector<const uint8_t> literal);
|
||||
const AstRawString* GetTwoByteString(Vector<const uint16_t> literal);
|
||||
const AstRawString* GetString(Handle<String> literal);
|
||||
const AstConsString* NewConsString(const AstString* left,
|
||||
const AstString* right);
|
||||
|
||||
void Internalize(Isolate* isolate);
|
||||
bool IsInternalized() {
|
||||
return isolate_ != NULL;
|
||||
}
|
||||
|
||||
#define F(name, str) \
|
||||
const AstRawString* name##_string() { \
|
||||
if (name##_string_ == NULL) { \
|
||||
const char* data = str; \
|
||||
name##_string_ = GetOneByteString( \
|
||||
Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), \
|
||||
static_cast<int>(strlen(data)))); \
|
||||
} \
|
||||
return name##_string_; \
|
||||
}
|
||||
STRING_CONSTANTS(F)
|
||||
#undef F
|
||||
|
||||
const AstValue* NewString(const AstRawString* string);
|
||||
// A JavaScript symbol (ECMA-262 edition 6).
|
||||
const AstValue* NewSymbol(const char* name);
|
||||
const AstValue* NewNumber(double number);
|
||||
const AstValue* NewSmi(int number);
|
||||
const AstValue* NewBoolean(bool b);
|
||||
const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
|
||||
const AstValue* NewNull();
|
||||
const AstValue* NewUndefined();
|
||||
const AstValue* NewTheHole();
|
||||
|
||||
private:
|
||||
const AstRawString* GetString(uint32_t hash, bool is_one_byte,
|
||||
Vector<const byte> literal_bytes);
|
||||
|
||||
// All strings are copied here, one after another (no NULLs inbetween).
|
||||
HashMap string_table_;
|
||||
// For keeping track of all AstValues and AstRawStrings we've created (so that
|
||||
// they can be internalized later).
|
||||
List<AstValue*> values_;
|
||||
List<AstString*> strings_;
|
||||
Zone* zone_;
|
||||
Isolate* isolate_;
|
||||
|
||||
uint32_t hash_seed_;
|
||||
|
||||
#define F(name, str) \
|
||||
const AstRawString* name##_string_;
|
||||
STRING_CONSTANTS(F)
|
||||
#undef F
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#undef STRING_CONSTANTS
|
||||
|
||||
#endif // V8_AST_VALUE_FACTORY_H_
|
34
src/ast.cc
34
src/ast.cc
@ -55,14 +55,13 @@ bool Expression::IsUndefinedLiteral(Isolate* isolate) const {
|
||||
// The global identifier "undefined" is immutable. Everything
|
||||
// else could be reassigned.
|
||||
return var != NULL && var->location() == Variable::UNALLOCATED &&
|
||||
String::Equals(var_proxy->name(),
|
||||
isolate->factory()->undefined_string());
|
||||
var_proxy->raw_name()->IsOneByteEqualTo("undefined");
|
||||
}
|
||||
|
||||
|
||||
VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
|
||||
: Expression(zone, position),
|
||||
name_(var->name()),
|
||||
name_(var->raw_name()),
|
||||
var_(NULL), // Will be set by the call to BindTo.
|
||||
is_this_(var->is_this()),
|
||||
is_trivial_(false),
|
||||
@ -73,7 +72,7 @@ VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
|
||||
|
||||
|
||||
VariableProxy::VariableProxy(Zone* zone,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
bool is_this,
|
||||
Interface* interface,
|
||||
int position)
|
||||
@ -84,8 +83,6 @@ VariableProxy::VariableProxy(Zone* zone,
|
||||
is_trivial_(false),
|
||||
is_lvalue_(false),
|
||||
interface_(interface) {
|
||||
// Names must be canonicalized for fast equality checks.
|
||||
ASSERT(name->IsInternalizedString());
|
||||
}
|
||||
|
||||
|
||||
@ -93,7 +90,7 @@ void VariableProxy::BindTo(Variable* var) {
|
||||
ASSERT(var_ == NULL); // must be bound only once
|
||||
ASSERT(var != NULL); // must bind
|
||||
ASSERT(!FLAG_harmony_modules || interface_->IsUnified(var->interface()));
|
||||
ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name()));
|
||||
ASSERT((is_this() && var->is_this()) || name_ == var->raw_name());
|
||||
// Ideally CONST-ness should match. However, this is very hard to achieve
|
||||
// because we don't know the exact semantics of conflicting (const and
|
||||
// non-const) multiple variable declarations, const vars introduced via
|
||||
@ -180,15 +177,13 @@ void FunctionLiteral::InitializeSharedInfo(
|
||||
}
|
||||
|
||||
|
||||
ObjectLiteralProperty::ObjectLiteralProperty(
|
||||
Zone* zone, Literal* key, Expression* value) {
|
||||
ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone,
|
||||
AstValueFactory* ast_value_factory,
|
||||
Literal* key, Expression* value) {
|
||||
emit_store_ = true;
|
||||
key_ = key;
|
||||
value_ = value;
|
||||
Handle<Object> k = key->value();
|
||||
if (k->IsInternalizedString() &&
|
||||
String::Equals(Handle<String>::cast(k),
|
||||
zone->isolate()->factory()->proto_string())) {
|
||||
if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) {
|
||||
kind_ = PROTOTYPE;
|
||||
} else if (value_->AsMaterializedLiteral() != NULL) {
|
||||
kind_ = MATERIALIZED_LITERAL;
|
||||
@ -1122,9 +1117,8 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
|
||||
// optimize them.
|
||||
add_flag(kDontInline);
|
||||
} else if (node->function()->intrinsic_type == Runtime::INLINE &&
|
||||
(node->name()->IsOneByteEqualTo(
|
||||
STATIC_ASCII_VECTOR("_ArgumentsLength")) ||
|
||||
node->name()->IsOneByteEqualTo(STATIC_ASCII_VECTOR("_Arguments")))) {
|
||||
(node->raw_name()->IsOneByteEqualTo("_ArgumentsLength") ||
|
||||
node->raw_name()->IsOneByteEqualTo("_Arguments"))) {
|
||||
// Don't inline the %_ArgumentsLength or %_Arguments because their
|
||||
// implementation will not work. There is no stack frame to get them
|
||||
// from.
|
||||
@ -1139,17 +1133,17 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
|
||||
|
||||
|
||||
Handle<String> Literal::ToString() {
|
||||
if (value_->IsString()) return Handle<String>::cast(value_);
|
||||
if (value_->IsString()) return value_->AsString()->string();
|
||||
ASSERT(value_->IsNumber());
|
||||
char arr[100];
|
||||
Vector<char> buffer(arr, ARRAY_SIZE(arr));
|
||||
const char* str;
|
||||
if (value_->IsSmi()) {
|
||||
if (value()->IsSmi()) {
|
||||
// Optimization only, the heap number case would subsume this.
|
||||
SNPrintF(buffer, "%d", Smi::cast(*value_)->value());
|
||||
SNPrintF(buffer, "%d", Smi::cast(*value())->value());
|
||||
str = arr;
|
||||
} else {
|
||||
str = DoubleToCString(value_->Number(), buffer);
|
||||
str = DoubleToCString(value()->Number(), buffer);
|
||||
}
|
||||
return isolate_->factory()->NewStringFromAsciiChecked(str);
|
||||
}
|
||||
|
240
src/ast.h
240
src/ast.h
@ -8,6 +8,7 @@
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/ast-value-factory.h"
|
||||
#include "src/factory.h"
|
||||
#include "src/feedback-slots.h"
|
||||
#include "src/interface.h"
|
||||
@ -367,11 +368,14 @@ class Expression : public AstNode {
|
||||
protected:
|
||||
Expression(Zone* zone, int pos)
|
||||
: AstNode(pos),
|
||||
zone_(zone),
|
||||
bounds_(Bounds::Unbounded(zone)),
|
||||
id_(GetNextId(zone)),
|
||||
test_id_(GetNextId(zone)) {}
|
||||
void set_to_boolean_types(byte types) { to_boolean_types_ = types; }
|
||||
|
||||
Zone* zone_;
|
||||
|
||||
private:
|
||||
Bounds bounds_;
|
||||
byte to_boolean_types_;
|
||||
@ -390,7 +394,7 @@ class BreakableStatement : public Statement {
|
||||
|
||||
// The labels associated with this statement. May be NULL;
|
||||
// if it is != NULL, guaranteed to contain at least one entry.
|
||||
ZoneStringList* labels() const { return labels_; }
|
||||
ZoneList<const AstRawString*>* labels() const { return labels_; }
|
||||
|
||||
// Type testing & conversion.
|
||||
virtual BreakableStatement* AsBreakableStatement() V8_FINAL V8_OVERRIDE {
|
||||
@ -410,7 +414,7 @@ class BreakableStatement : public Statement {
|
||||
|
||||
protected:
|
||||
BreakableStatement(
|
||||
Zone* zone, ZoneStringList* labels,
|
||||
Zone* zone, ZoneList<const AstRawString*>* labels,
|
||||
BreakableType breakable_type, int position)
|
||||
: Statement(zone, position),
|
||||
labels_(labels),
|
||||
@ -422,7 +426,7 @@ class BreakableStatement : public Statement {
|
||||
|
||||
|
||||
private:
|
||||
ZoneStringList* labels_;
|
||||
ZoneList<const AstRawString*>* labels_;
|
||||
BreakableType breakable_type_;
|
||||
Label break_target_;
|
||||
const BailoutId entry_id_;
|
||||
@ -453,7 +457,7 @@ class Block V8_FINAL : public BreakableStatement {
|
||||
|
||||
protected:
|
||||
Block(Zone* zone,
|
||||
ZoneStringList* labels,
|
||||
ZoneList<const AstRawString*>* labels,
|
||||
int capacity,
|
||||
bool is_initializer_block,
|
||||
int pos)
|
||||
@ -662,18 +666,15 @@ class ModulePath V8_FINAL : public Module {
|
||||
DECLARE_NODE_TYPE(ModulePath)
|
||||
|
||||
Module* module() const { return module_; }
|
||||
Handle<String> name() const { return name_; }
|
||||
Handle<String> name() const { return name_->string(); }
|
||||
|
||||
protected:
|
||||
ModulePath(Zone* zone, Module* module, Handle<String> name, int pos)
|
||||
: Module(zone, pos),
|
||||
module_(module),
|
||||
name_(name) {
|
||||
}
|
||||
ModulePath(Zone* zone, Module* module, const AstRawString* name, int pos)
|
||||
: Module(zone, pos), module_(module), name_(name) {}
|
||||
|
||||
private:
|
||||
Module* module_;
|
||||
Handle<String> name_;
|
||||
const AstRawString* name_;
|
||||
};
|
||||
|
||||
|
||||
@ -730,7 +731,7 @@ class IterationStatement : public BreakableStatement {
|
||||
Label* continue_target() { return &continue_target_; }
|
||||
|
||||
protected:
|
||||
IterationStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
IterationStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos),
|
||||
body_(NULL),
|
||||
osr_entry_id_(GetNextId(zone)) {
|
||||
@ -764,7 +765,7 @@ class DoWhileStatement V8_FINAL : public IterationStatement {
|
||||
BailoutId BackEdgeId() const { return back_edge_id_; }
|
||||
|
||||
protected:
|
||||
DoWhileStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
DoWhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: IterationStatement(zone, labels, pos),
|
||||
cond_(NULL),
|
||||
continue_id_(GetNextId(zone)),
|
||||
@ -801,7 +802,7 @@ class WhileStatement V8_FINAL : public IterationStatement {
|
||||
BailoutId BodyId() const { return body_id_; }
|
||||
|
||||
protected:
|
||||
WhileStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
WhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: IterationStatement(zone, labels, pos),
|
||||
cond_(NULL),
|
||||
may_have_function_literal_(true),
|
||||
@ -852,7 +853,7 @@ class ForStatement V8_FINAL : public IterationStatement {
|
||||
void set_loop_variable(Variable* var) { loop_variable_ = var; }
|
||||
|
||||
protected:
|
||||
ForStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
ForStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: IterationStatement(zone, labels, pos),
|
||||
init_(NULL),
|
||||
cond_(NULL),
|
||||
@ -894,11 +895,8 @@ class ForEachStatement : public IterationStatement {
|
||||
Expression* subject() const { return subject_; }
|
||||
|
||||
protected:
|
||||
ForEachStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
: IterationStatement(zone, labels, pos),
|
||||
each_(NULL),
|
||||
subject_(NULL) {
|
||||
}
|
||||
ForEachStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: IterationStatement(zone, labels, pos), each_(NULL), subject_(NULL) {}
|
||||
|
||||
private:
|
||||
Expression* each_;
|
||||
@ -934,7 +932,7 @@ class ForInStatement V8_FINAL : public ForEachStatement,
|
||||
virtual BailoutId StackCheckId() const V8_OVERRIDE { return body_id_; }
|
||||
|
||||
protected:
|
||||
ForInStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
ForInStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: ForEachStatement(zone, labels, pos),
|
||||
for_in_type_(SLOW_FOR_IN),
|
||||
for_in_feedback_slot_(kInvalidFeedbackSlot),
|
||||
@ -1004,7 +1002,7 @@ class ForOfStatement V8_FINAL : public ForEachStatement {
|
||||
BailoutId BackEdgeId() const { return back_edge_id_; }
|
||||
|
||||
protected:
|
||||
ForOfStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
ForOfStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: ForEachStatement(zone, labels, pos),
|
||||
assign_iterator_(NULL),
|
||||
next_result_(NULL),
|
||||
@ -1165,7 +1163,7 @@ class SwitchStatement V8_FINAL : public BreakableStatement {
|
||||
ZoneList<CaseClause*>* cases() const { return cases_; }
|
||||
|
||||
protected:
|
||||
SwitchStatement(Zone* zone, ZoneStringList* labels, int pos)
|
||||
SwitchStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
|
||||
: BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos),
|
||||
tag_(NULL),
|
||||
cases_(NULL) { }
|
||||
@ -1345,26 +1343,28 @@ class Literal V8_FINAL : public Expression {
|
||||
DECLARE_NODE_TYPE(Literal)
|
||||
|
||||
virtual bool IsPropertyName() const V8_OVERRIDE {
|
||||
if (value_->IsInternalizedString()) {
|
||||
uint32_t ignored;
|
||||
return !String::cast(*value_)->AsArrayIndex(&ignored);
|
||||
}
|
||||
return false;
|
||||
return value_->IsPropertyName();
|
||||
}
|
||||
|
||||
Handle<String> AsPropertyName() {
|
||||
ASSERT(IsPropertyName());
|
||||
return Handle<String>::cast(value_);
|
||||
return Handle<String>::cast(value());
|
||||
}
|
||||
|
||||
const AstRawString* AsRawPropertyName() {
|
||||
ASSERT(IsPropertyName());
|
||||
return value_->AsString();
|
||||
}
|
||||
|
||||
virtual bool ToBooleanIsTrue() const V8_OVERRIDE {
|
||||
return value_->BooleanValue();
|
||||
return value()->BooleanValue();
|
||||
}
|
||||
virtual bool ToBooleanIsFalse() const V8_OVERRIDE {
|
||||
return !value_->BooleanValue();
|
||||
return !value()->BooleanValue();
|
||||
}
|
||||
|
||||
Handle<Object> value() const { return value_; }
|
||||
Handle<Object> value() const { return value_->value(); }
|
||||
const AstValue* raw_value() const { return value_; }
|
||||
|
||||
// Support for using Literal as a HashMap key. NOTE: Currently, this works
|
||||
// only for string and number literals!
|
||||
@ -1379,7 +1379,7 @@ class Literal V8_FINAL : public Expression {
|
||||
TypeFeedbackId LiteralFeedbackId() const { return reuse(id()); }
|
||||
|
||||
protected:
|
||||
Literal(Zone* zone, Handle<Object> value, int position)
|
||||
Literal(Zone* zone, const AstValue* value, int position)
|
||||
: Expression(zone, position),
|
||||
value_(value),
|
||||
isolate_(zone->isolate()) { }
|
||||
@ -1387,7 +1387,7 @@ class Literal V8_FINAL : public Expression {
|
||||
private:
|
||||
Handle<String> ToString();
|
||||
|
||||
Handle<Object> value_;
|
||||
const AstValue* value_;
|
||||
// TODO(dcarney): remove. this is only needed for Match and Hash.
|
||||
Isolate* isolate_;
|
||||
};
|
||||
@ -1458,7 +1458,8 @@ class ObjectLiteralProperty V8_FINAL : public ZoneObject {
|
||||
PROTOTYPE // Property is __proto__.
|
||||
};
|
||||
|
||||
ObjectLiteralProperty(Zone* zone, Literal* key, Expression* value);
|
||||
ObjectLiteralProperty(Zone* zone, AstValueFactory* ast_value_factory,
|
||||
Literal* key, Expression* value);
|
||||
|
||||
Literal* key() { return key_; }
|
||||
Expression* value() { return value_; }
|
||||
@ -1557,13 +1558,13 @@ class RegExpLiteral V8_FINAL : public MaterializedLiteral {
|
||||
public:
|
||||
DECLARE_NODE_TYPE(RegExpLiteral)
|
||||
|
||||
Handle<String> pattern() const { return pattern_; }
|
||||
Handle<String> flags() const { return flags_; }
|
||||
Handle<String> pattern() const { return pattern_->string(); }
|
||||
Handle<String> flags() const { return flags_->string(); }
|
||||
|
||||
protected:
|
||||
RegExpLiteral(Zone* zone,
|
||||
Handle<String> pattern,
|
||||
Handle<String> flags,
|
||||
const AstRawString* pattern,
|
||||
const AstRawString* flags,
|
||||
int literal_index,
|
||||
int pos)
|
||||
: MaterializedLiteral(zone, literal_index, pos),
|
||||
@ -1573,8 +1574,8 @@ class RegExpLiteral V8_FINAL : public MaterializedLiteral {
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<String> pattern_;
|
||||
Handle<String> flags_;
|
||||
const AstRawString* pattern_;
|
||||
const AstRawString* flags_;
|
||||
};
|
||||
|
||||
|
||||
@ -1625,15 +1626,12 @@ class VariableProxy V8_FINAL : public Expression {
|
||||
return var_ == NULL ? true : var_->IsValidReference();
|
||||
}
|
||||
|
||||
bool IsVariable(Handle<String> n) const {
|
||||
return !is_this() && name().is_identical_to(n);
|
||||
}
|
||||
|
||||
bool IsArguments() const { return var_ != NULL && var_->is_arguments(); }
|
||||
|
||||
bool IsLValue() const { return is_lvalue_; }
|
||||
|
||||
Handle<String> name() const { return name_; }
|
||||
Handle<String> name() const { return name_->string(); }
|
||||
const AstRawString* raw_name() const { return name_; }
|
||||
Variable* var() const { return var_; }
|
||||
bool is_this() const { return is_this_; }
|
||||
Interface* interface() const { return interface_; }
|
||||
@ -1649,12 +1647,12 @@ class VariableProxy V8_FINAL : public Expression {
|
||||
VariableProxy(Zone* zone, Variable* var, int position);
|
||||
|
||||
VariableProxy(Zone* zone,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
bool is_this,
|
||||
Interface* interface,
|
||||
int position);
|
||||
|
||||
Handle<String> name_;
|
||||
const AstRawString* name_;
|
||||
Variable* var_; // resolved variable, or NULL
|
||||
bool is_this_;
|
||||
bool is_trivial_;
|
||||
@ -1900,7 +1898,8 @@ class CallRuntime V8_FINAL : public Expression {
|
||||
public:
|
||||
DECLARE_NODE_TYPE(CallRuntime)
|
||||
|
||||
Handle<String> name() const { return name_; }
|
||||
Handle<String> name() const { return raw_name_->string(); }
|
||||
const AstRawString* raw_name() const { return raw_name_; }
|
||||
const Runtime::Function* function() const { return function_; }
|
||||
ZoneList<Expression*>* arguments() const { return arguments_; }
|
||||
bool is_jsruntime() const { return function_ == NULL; }
|
||||
@ -1909,17 +1908,17 @@ class CallRuntime V8_FINAL : public Expression {
|
||||
|
||||
protected:
|
||||
CallRuntime(Zone* zone,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
const Runtime::Function* function,
|
||||
ZoneList<Expression*>* arguments,
|
||||
int pos)
|
||||
: Expression(zone, pos),
|
||||
name_(name),
|
||||
raw_name_(name),
|
||||
function_(function),
|
||||
arguments_(arguments) { }
|
||||
|
||||
private:
|
||||
Handle<String> name_;
|
||||
const AstRawString* raw_name_;
|
||||
const Runtime::Function* function_;
|
||||
ZoneList<Expression*>* arguments_;
|
||||
};
|
||||
@ -2313,7 +2312,8 @@ class FunctionLiteral V8_FINAL : public Expression {
|
||||
|
||||
DECLARE_NODE_TYPE(FunctionLiteral)
|
||||
|
||||
Handle<String> name() const { return name_; }
|
||||
Handle<String> name() const { return raw_name_->string(); }
|
||||
const AstRawString* raw_name() const { return raw_name_; }
|
||||
Scope* scope() const { return scope_; }
|
||||
ZoneList<Statement*>* body() const { return body_; }
|
||||
void set_function_token_position(int pos) { function_token_position_ = pos; }
|
||||
@ -2336,13 +2336,37 @@ class FunctionLiteral V8_FINAL : public Expression {
|
||||
void InitializeSharedInfo(Handle<Code> code);
|
||||
|
||||
Handle<String> debug_name() const {
|
||||
if (name_->length() > 0) return name_;
|
||||
if (raw_name_ != NULL && !raw_name_->IsEmpty()) {
|
||||
return raw_name_->string();
|
||||
}
|
||||
return inferred_name();
|
||||
}
|
||||
|
||||
Handle<String> inferred_name() const { return inferred_name_; }
|
||||
Handle<String> inferred_name() const {
|
||||
if (!inferred_name_.is_null()) {
|
||||
ASSERT(raw_inferred_name_ == NULL);
|
||||
return inferred_name_;
|
||||
}
|
||||
if (raw_inferred_name_ != NULL) {
|
||||
return raw_inferred_name_->string();
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Handle<String>();
|
||||
}
|
||||
|
||||
// Only one of {set_inferred_name, set_raw_inferred_name} should be called.
|
||||
void set_inferred_name(Handle<String> inferred_name) {
|
||||
ASSERT(!inferred_name.is_null());
|
||||
inferred_name_ = inferred_name;
|
||||
ASSERT(raw_inferred_name_== NULL || raw_inferred_name_->IsEmpty());
|
||||
raw_inferred_name_ = NULL;
|
||||
}
|
||||
|
||||
void set_raw_inferred_name(const AstString* raw_inferred_name) {
|
||||
ASSERT(raw_inferred_name != NULL);
|
||||
raw_inferred_name_ = raw_inferred_name;
|
||||
ASSERT(inferred_name_.is_null());
|
||||
inferred_name_ = Handle<String>();
|
||||
}
|
||||
|
||||
// shared_info may be null if it's not cached in full code.
|
||||
@ -2389,7 +2413,8 @@ class FunctionLiteral V8_FINAL : public Expression {
|
||||
|
||||
protected:
|
||||
FunctionLiteral(Zone* zone,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
AstValueFactory* ast_value_factory,
|
||||
Scope* scope,
|
||||
ZoneList<Statement*>* body,
|
||||
int materialized_literal_count,
|
||||
@ -2403,10 +2428,10 @@ class FunctionLiteral V8_FINAL : public Expression {
|
||||
IsGeneratorFlag is_generator,
|
||||
int position)
|
||||
: Expression(zone, position),
|
||||
name_(name),
|
||||
raw_name_(name),
|
||||
scope_(scope),
|
||||
body_(body),
|
||||
inferred_name_(zone->isolate()->factory()->empty_string()),
|
||||
raw_inferred_name_(ast_value_factory->empty_string()),
|
||||
dont_optimize_reason_(kNoReason),
|
||||
materialized_literal_count_(materialized_literal_count),
|
||||
expected_property_count_(expected_property_count),
|
||||
@ -2424,10 +2449,12 @@ class FunctionLiteral V8_FINAL : public Expression {
|
||||
}
|
||||
|
||||
private:
|
||||
const AstRawString* raw_name_;
|
||||
Handle<String> name_;
|
||||
Handle<SharedFunctionInfo> shared_info_;
|
||||
Scope* scope_;
|
||||
ZoneList<Statement*>* body_;
|
||||
const AstString* raw_inferred_name_;
|
||||
Handle<String> inferred_name_;
|
||||
AstProperties ast_properties_;
|
||||
BailoutReason dont_optimize_reason_;
|
||||
@ -2453,16 +2480,16 @@ class NativeFunctionLiteral V8_FINAL : public Expression {
|
||||
public:
|
||||
DECLARE_NODE_TYPE(NativeFunctionLiteral)
|
||||
|
||||
Handle<String> name() const { return name_; }
|
||||
Handle<String> name() const { return name_->string(); }
|
||||
v8::Extension* extension() const { return extension_; }
|
||||
|
||||
protected:
|
||||
NativeFunctionLiteral(
|
||||
Zone* zone, Handle<String> name, v8::Extension* extension, int pos)
|
||||
NativeFunctionLiteral(Zone* zone, const AstRawString* name,
|
||||
v8::Extension* extension, int pos)
|
||||
: Expression(zone, pos), name_(name), extension_(extension) {}
|
||||
|
||||
private:
|
||||
Handle<String> name_;
|
||||
const AstRawString* name_;
|
||||
v8::Extension* extension_;
|
||||
};
|
||||
|
||||
@ -2954,7 +2981,8 @@ class AstNullVisitor BASE_EMBEDDED {
|
||||
template<class Visitor>
|
||||
class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
public:
|
||||
explicit AstNodeFactory(Zone* zone) : zone_(zone) { }
|
||||
explicit AstNodeFactory(Zone* zone, AstValueFactory* ast_value_factory)
|
||||
: zone_(zone), ast_value_factory_(ast_value_factory) {}
|
||||
|
||||
Visitor* visitor() { return &visitor_; }
|
||||
|
||||
@ -3018,8 +3046,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
VISIT_AND_RETURN(ModuleVariable, module)
|
||||
}
|
||||
|
||||
ModulePath* NewModulePath(Module* origin, Handle<String> name, int pos) {
|
||||
ModulePath* module = new(zone_) ModulePath(zone_, origin, name, pos);
|
||||
ModulePath* NewModulePath(Module* origin, const AstRawString* name, int pos) {
|
||||
ModulePath* module = new (zone_) ModulePath(zone_, origin, name, pos);
|
||||
VISIT_AND_RETURN(ModulePath, module)
|
||||
}
|
||||
|
||||
@ -3028,7 +3056,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
VISIT_AND_RETURN(ModuleUrl, module)
|
||||
}
|
||||
|
||||
Block* NewBlock(ZoneStringList* labels,
|
||||
Block* NewBlock(ZoneList<const AstRawString*>* labels,
|
||||
int capacity,
|
||||
bool is_initializer_block,
|
||||
int pos) {
|
||||
@ -3038,7 +3066,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
#define STATEMENT_WITH_LABELS(NodeType) \
|
||||
NodeType* New##NodeType(ZoneStringList* labels, int pos) { \
|
||||
NodeType* New##NodeType(ZoneList<const AstRawString*>* labels, int pos) { \
|
||||
NodeType* stmt = new(zone_) NodeType(zone_, labels, pos); \
|
||||
VISIT_AND_RETURN(NodeType, stmt); \
|
||||
}
|
||||
@ -3049,7 +3077,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
#undef STATEMENT_WITH_LABELS
|
||||
|
||||
ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode,
|
||||
ZoneStringList* labels,
|
||||
ZoneList<const AstRawString*>* labels,
|
||||
int pos) {
|
||||
switch (visit_mode) {
|
||||
case ForEachStatement::ENUMERATE: {
|
||||
@ -3146,14 +3174,60 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
VISIT_AND_RETURN(CaseClause, clause)
|
||||
}
|
||||
|
||||
Literal* NewLiteral(Handle<Object> handle, int pos) {
|
||||
Literal* lit = new(zone_) Literal(zone_, handle, pos);
|
||||
Literal* NewStringLiteral(const AstRawString* string, int pos) {
|
||||
Literal* lit =
|
||||
new (zone_) Literal(zone_, ast_value_factory_->NewString(string), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
// A JavaScript symbol (ECMA-262 edition 6).
|
||||
Literal* NewSymbolLiteral(const char* name, int pos) {
|
||||
Literal* lit =
|
||||
new (zone_) Literal(zone_, ast_value_factory_->NewSymbol(name), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
Literal* NewNumberLiteral(double number, int pos) {
|
||||
return NewLiteral(
|
||||
zone_->isolate()->factory()->NewNumber(number, TENURED), pos);
|
||||
Literal* lit = new (zone_)
|
||||
Literal(zone_, ast_value_factory_->NewNumber(number), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
Literal* NewSmiLiteral(int number, int pos) {
|
||||
Literal* lit =
|
||||
new (zone_) Literal(zone_, ast_value_factory_->NewSmi(number), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
Literal* NewBooleanLiteral(bool b, int pos) {
|
||||
Literal* lit =
|
||||
new (zone_) Literal(zone_, ast_value_factory_->NewBoolean(b), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
Literal* NewStringListLiteral(ZoneList<const AstRawString*>* strings,
|
||||
int pos) {
|
||||
Literal* lit = new (zone_)
|
||||
Literal(zone_, ast_value_factory_->NewStringList(strings), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
Literal* NewNullLiteral(int pos) {
|
||||
Literal* lit =
|
||||
new (zone_) Literal(zone_, ast_value_factory_->NewNull(), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
Literal* NewUndefinedLiteral(int pos) {
|
||||
Literal* lit =
|
||||
new (zone_) Literal(zone_, ast_value_factory_->NewUndefined(), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
Literal* NewTheHoleLiteral(int pos) {
|
||||
Literal* lit =
|
||||
new (zone_) Literal(zone_, ast_value_factory_->NewTheHole(), pos);
|
||||
VISIT_AND_RETURN(Literal, lit)
|
||||
}
|
||||
|
||||
ObjectLiteral* NewObjectLiteral(
|
||||
@ -3170,7 +3244,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
|
||||
ObjectLiteral::Property* NewObjectLiteralProperty(Literal* key,
|
||||
Expression* value) {
|
||||
return new(zone_) ObjectLiteral::Property(zone_, key, value);
|
||||
return new (zone_)
|
||||
ObjectLiteral::Property(zone_, ast_value_factory_, key, value);
|
||||
}
|
||||
|
||||
ObjectLiteral::Property* NewObjectLiteralProperty(bool is_getter,
|
||||
@ -3178,12 +3253,12 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
int pos) {
|
||||
ObjectLiteral::Property* prop =
|
||||
new(zone_) ObjectLiteral::Property(zone_, is_getter, value);
|
||||
prop->set_key(NewLiteral(value->name(), pos));
|
||||
prop->set_key(NewStringLiteral(value->raw_name(), pos));
|
||||
return prop; // Not an AST node, will not be visited.
|
||||
}
|
||||
|
||||
RegExpLiteral* NewRegExpLiteral(Handle<String> pattern,
|
||||
Handle<String> flags,
|
||||
RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern,
|
||||
const AstRawString* flags,
|
||||
int literal_index,
|
||||
int pos) {
|
||||
RegExpLiteral* lit =
|
||||
@ -3205,7 +3280,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
VISIT_AND_RETURN(VariableProxy, proxy)
|
||||
}
|
||||
|
||||
VariableProxy* NewVariableProxy(Handle<String> name,
|
||||
VariableProxy* NewVariableProxy(const AstRawString* name,
|
||||
bool is_this,
|
||||
Interface* interface = Interface::NewValue(),
|
||||
int position = RelocInfo::kNoPosition) {
|
||||
@ -3233,7 +3308,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
VISIT_AND_RETURN(CallNew, call)
|
||||
}
|
||||
|
||||
CallRuntime* NewCallRuntime(Handle<String> name,
|
||||
CallRuntime* NewCallRuntime(const AstRawString* name,
|
||||
const Runtime::Function* function,
|
||||
ZoneList<Expression*>* arguments,
|
||||
int pos) {
|
||||
@ -3311,7 +3386,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
FunctionLiteral* NewFunctionLiteral(
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
AstValueFactory* ast_value_factory,
|
||||
Scope* scope,
|
||||
ZoneList<Statement*>* body,
|
||||
int materialized_literal_count,
|
||||
@ -3325,7 +3401,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
FunctionLiteral::IsGeneratorFlag is_generator,
|
||||
int position) {
|
||||
FunctionLiteral* lit = new(zone_) FunctionLiteral(
|
||||
zone_, name, scope, body,
|
||||
zone_, name, ast_value_factory, scope, body,
|
||||
materialized_literal_count, expected_property_count, handler_count,
|
||||
parameter_count, function_type, has_duplicate_parameters, is_function,
|
||||
is_parenthesized, is_generator, position);
|
||||
@ -3337,7 +3413,8 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
NativeFunctionLiteral* NewNativeFunctionLiteral(
|
||||
Handle<String> name, v8::Extension* extension, int pos) {
|
||||
const AstRawString* name, v8::Extension* extension,
|
||||
int pos) {
|
||||
NativeFunctionLiteral* lit =
|
||||
new(zone_) NativeFunctionLiteral(zone_, name, extension, pos);
|
||||
VISIT_AND_RETURN(NativeFunctionLiteral, lit)
|
||||
@ -3353,6 +3430,7 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED {
|
||||
private:
|
||||
Zone* zone_;
|
||||
Visitor visitor_;
|
||||
AstValueFactory* ast_value_factory_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,7 +38,9 @@ CompilationInfo::CompilationInfo(Handle<Script> script,
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true),
|
||||
optimization_id_(-1) {
|
||||
optimization_id_(-1),
|
||||
ast_value_factory_(NULL),
|
||||
ast_value_factory_owned_(false) {
|
||||
Initialize(script->GetIsolate(), BASE, zone);
|
||||
}
|
||||
|
||||
@ -51,7 +53,9 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true),
|
||||
optimization_id_(-1) {
|
||||
optimization_id_(-1),
|
||||
ast_value_factory_(NULL),
|
||||
ast_value_factory_owned_(false) {
|
||||
Initialize(script_->GetIsolate(), BASE, zone);
|
||||
}
|
||||
|
||||
@ -66,7 +70,9 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure,
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true),
|
||||
optimization_id_(-1) {
|
||||
optimization_id_(-1),
|
||||
ast_value_factory_(NULL),
|
||||
ast_value_factory_owned_(false) {
|
||||
Initialize(script_->GetIsolate(), BASE, zone);
|
||||
}
|
||||
|
||||
@ -78,7 +84,9 @@ CompilationInfo::CompilationInfo(HydrogenCodeStub* stub,
|
||||
osr_ast_id_(BailoutId::None()),
|
||||
parameter_count_(0),
|
||||
this_has_uses_(true),
|
||||
optimization_id_(-1) {
|
||||
optimization_id_(-1),
|
||||
ast_value_factory_(NULL),
|
||||
ast_value_factory_owned_(false) {
|
||||
Initialize(isolate, STUB, zone);
|
||||
code_stub_ = stub;
|
||||
}
|
||||
@ -131,6 +139,7 @@ void CompilationInfo::Initialize(Isolate* isolate,
|
||||
CompilationInfo::~CompilationInfo() {
|
||||
delete deferred_handles_;
|
||||
delete no_frame_ranges_;
|
||||
if (ast_value_factory_owned_) delete ast_value_factory_;
|
||||
#ifdef DEBUG
|
||||
// Check that no dependent maps have been added or added dependent maps have
|
||||
// been rolled back or committed.
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class AstValueFactory;
|
||||
class ScriptData;
|
||||
class HydrogenCodeStub;
|
||||
|
||||
@ -321,6 +322,13 @@ class CompilationInfo {
|
||||
|
||||
int optimization_id() const { return optimization_id_; }
|
||||
|
||||
AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
|
||||
void SetAstValueFactory(AstValueFactory* ast_value_factory,
|
||||
bool owned = true) {
|
||||
ast_value_factory_ = ast_value_factory;
|
||||
ast_value_factory_owned_ = owned;
|
||||
}
|
||||
|
||||
protected:
|
||||
CompilationInfo(Handle<Script> script,
|
||||
Zone* zone);
|
||||
@ -464,6 +472,9 @@ class CompilationInfo {
|
||||
|
||||
int optimization_id_;
|
||||
|
||||
AstValueFactory* ast_value_factory_;
|
||||
bool ast_value_factory_owned_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
|
||||
};
|
||||
|
||||
|
@ -5,14 +5,16 @@
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/ast.h"
|
||||
#include "src/ast-value-factory.h"
|
||||
#include "src/func-name-inferrer.h"
|
||||
#include "src/list-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
FuncNameInferrer::FuncNameInferrer(Isolate* isolate, Zone* zone)
|
||||
: isolate_(isolate),
|
||||
FuncNameInferrer::FuncNameInferrer(AstValueFactory* ast_value_factory,
|
||||
Zone* zone)
|
||||
: ast_value_factory_(ast_value_factory),
|
||||
entries_stack_(10, zone),
|
||||
names_stack_(5, zone),
|
||||
funcs_to_infer_(4, zone),
|
||||
@ -20,40 +22,36 @@ FuncNameInferrer::FuncNameInferrer(Isolate* isolate, Zone* zone)
|
||||
}
|
||||
|
||||
|
||||
void FuncNameInferrer::PushEnclosingName(Handle<String> name) {
|
||||
void FuncNameInferrer::PushEnclosingName(const AstRawString* name) {
|
||||
// Enclosing name is a name of a constructor function. To check
|
||||
// that it is really a constructor, we check that it is not empty
|
||||
// and starts with a capital letter.
|
||||
if (name->length() > 0 && Runtime::IsUpperCaseChar(
|
||||
isolate()->runtime_state(), name->Get(0))) {
|
||||
if (!name->IsEmpty() && unibrow::Uppercase::Is(name->FirstCharacter())) {
|
||||
names_stack_.Add(Name(name, kEnclosingConstructorName), zone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FuncNameInferrer::PushLiteralName(Handle<String> name) {
|
||||
if (IsOpen() &&
|
||||
!String::Equals(isolate()->factory()->prototype_string(), name)) {
|
||||
void FuncNameInferrer::PushLiteralName(const AstRawString* name) {
|
||||
if (IsOpen() && name != ast_value_factory_->prototype_string()) {
|
||||
names_stack_.Add(Name(name, kLiteralName), zone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FuncNameInferrer::PushVariableName(Handle<String> name) {
|
||||
if (IsOpen() &&
|
||||
!String::Equals(isolate()->factory()->dot_result_string(), name)) {
|
||||
void FuncNameInferrer::PushVariableName(const AstRawString* name) {
|
||||
if (IsOpen() && name != ast_value_factory_->dot_result_string()) {
|
||||
names_stack_.Add(Name(name, kVariableName), zone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle<String> FuncNameInferrer::MakeNameFromStack() {
|
||||
return MakeNameFromStackHelper(0, isolate()->factory()->empty_string());
|
||||
const AstString* FuncNameInferrer::MakeNameFromStack() {
|
||||
return MakeNameFromStackHelper(0, ast_value_factory_->empty_string());
|
||||
}
|
||||
|
||||
|
||||
Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
|
||||
Handle<String> prev) {
|
||||
const AstString* FuncNameInferrer::MakeNameFromStackHelper(
|
||||
int pos, const AstString* prev) {
|
||||
if (pos >= names_stack_.length()) return prev;
|
||||
if (pos < names_stack_.length() - 1 &&
|
||||
names_stack_.at(pos).type == kVariableName &&
|
||||
@ -62,12 +60,11 @@ Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
|
||||
return MakeNameFromStackHelper(pos + 1, prev);
|
||||
} else {
|
||||
if (prev->length() > 0) {
|
||||
Handle<String> name = names_stack_.at(pos).name;
|
||||
const AstRawString* name = names_stack_.at(pos).name;
|
||||
if (prev->length() + name->length() + 1 > String::kMaxLength) return prev;
|
||||
Factory* factory = isolate()->factory();
|
||||
Handle<String> curr =
|
||||
factory->NewConsString(factory->dot_string(), name).ToHandleChecked();
|
||||
curr = factory->NewConsString(prev, curr).ToHandleChecked();
|
||||
const AstConsString* curr = ast_value_factory_->NewConsString(
|
||||
ast_value_factory_->dot_string(), name);
|
||||
curr = ast_value_factory_->NewConsString(prev, curr);
|
||||
return MakeNameFromStackHelper(pos + 1, curr);
|
||||
} else {
|
||||
return MakeNameFromStackHelper(pos + 1, names_stack_.at(pos).name);
|
||||
@ -77,9 +74,9 @@ Handle<String> FuncNameInferrer::MakeNameFromStackHelper(int pos,
|
||||
|
||||
|
||||
void FuncNameInferrer::InferFunctionsNames() {
|
||||
Handle<String> func_name = MakeNameFromStack();
|
||||
const AstString* func_name = MakeNameFromStack();
|
||||
for (int i = 0; i < funcs_to_infer_.length(); ++i) {
|
||||
funcs_to_infer_[i]->set_inferred_name(func_name);
|
||||
funcs_to_infer_[i]->set_raw_inferred_name(func_name);
|
||||
}
|
||||
funcs_to_infer_.Rewind(0);
|
||||
}
|
||||
|
@ -11,8 +11,10 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class AstRawString;
|
||||
class AstString;
|
||||
class AstValueFactory;
|
||||
class FunctionLiteral;
|
||||
class Isolate;
|
||||
|
||||
// FuncNameInferrer is a stateful class that is used to perform name
|
||||
// inference for anonymous functions during static analysis of source code.
|
||||
@ -26,13 +28,13 @@ class Isolate;
|
||||
// a name.
|
||||
class FuncNameInferrer : public ZoneObject {
|
||||
public:
|
||||
FuncNameInferrer(Isolate* isolate, Zone* zone);
|
||||
FuncNameInferrer(AstValueFactory* ast_value_factory, Zone* zone);
|
||||
|
||||
// Returns whether we have entered name collection state.
|
||||
bool IsOpen() const { return !entries_stack_.is_empty(); }
|
||||
|
||||
// Pushes an enclosing the name of enclosing function onto names stack.
|
||||
void PushEnclosingName(Handle<String> name);
|
||||
void PushEnclosingName(const AstRawString* name);
|
||||
|
||||
// Enters name collection state.
|
||||
void Enter() {
|
||||
@ -40,9 +42,9 @@ class FuncNameInferrer : public ZoneObject {
|
||||
}
|
||||
|
||||
// Pushes an encountered name onto names stack when in collection state.
|
||||
void PushLiteralName(Handle<String> name);
|
||||
void PushLiteralName(const AstRawString* name);
|
||||
|
||||
void PushVariableName(Handle<String> name);
|
||||
void PushVariableName(const AstRawString* name);
|
||||
|
||||
// Adds a function to infer name for.
|
||||
void AddFunction(FunctionLiteral* func_to_infer) {
|
||||
@ -80,24 +82,24 @@ class FuncNameInferrer : public ZoneObject {
|
||||
kVariableName
|
||||
};
|
||||
struct Name {
|
||||
Name(Handle<String> name, NameType type) : name(name), type(type) { }
|
||||
Handle<String> name;
|
||||
Name(const AstRawString* name, NameType type) : name(name), type(type) {}
|
||||
const AstRawString* name;
|
||||
NameType type;
|
||||
};
|
||||
|
||||
Isolate* isolate() { return isolate_; }
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
// Constructs a full name in dotted notation from gathered names.
|
||||
Handle<String> MakeNameFromStack();
|
||||
const AstString* MakeNameFromStack();
|
||||
|
||||
// A helper function for MakeNameFromStack.
|
||||
Handle<String> MakeNameFromStackHelper(int pos, Handle<String> prev);
|
||||
const AstString* MakeNameFromStackHelper(int pos,
|
||||
const AstString* prev);
|
||||
|
||||
// Performs name inferring for added functions.
|
||||
void InferFunctionsNames();
|
||||
|
||||
Isolate* isolate_;
|
||||
AstValueFactory* ast_value_factory_;
|
||||
ZoneList<int> entries_stack_;
|
||||
ZoneList<Name> names_stack_;
|
||||
ZoneList<FunctionLiteral*> funcs_to_infer_;
|
||||
|
12
src/heap.h
12
src/heap.h
@ -277,16 +277,11 @@ namespace internal {
|
||||
V(constructor_string, "constructor") \
|
||||
V(dot_result_string, ".result") \
|
||||
V(dot_for_string, ".for.") \
|
||||
V(dot_iterable_string, ".iterable") \
|
||||
V(dot_iterator_string, ".iterator") \
|
||||
V(dot_generator_object_string, ".generator_object") \
|
||||
V(eval_string, "eval") \
|
||||
V(empty_string, "") \
|
||||
V(function_string, "function") \
|
||||
V(length_string, "length") \
|
||||
V(module_string, "module") \
|
||||
V(name_string, "name") \
|
||||
V(native_string, "native") \
|
||||
V(null_string, "null") \
|
||||
V(number_string, "number") \
|
||||
V(Number_string, "Number") \
|
||||
@ -312,7 +307,6 @@ namespace internal {
|
||||
V(private_api_string, "private_api") \
|
||||
V(private_intern_string, "private_intern") \
|
||||
V(Date_string, "Date") \
|
||||
V(this_string, "this") \
|
||||
V(to_string_string, "toString") \
|
||||
V(char_at_string, "CharAt") \
|
||||
V(undefined_string, "undefined") \
|
||||
@ -335,19 +329,13 @@ namespace internal {
|
||||
V(cell_value_string, "%cell_value") \
|
||||
V(function_class_string, "Function") \
|
||||
V(illegal_argument_string, "illegal argument") \
|
||||
V(MakeReferenceError_string, "MakeReferenceError") \
|
||||
V(MakeSyntaxError_string, "MakeSyntaxError") \
|
||||
V(MakeTypeError_string, "MakeTypeError") \
|
||||
V(unknown_label_string, "unknown_label") \
|
||||
V(space_string, " ") \
|
||||
V(exec_string, "exec") \
|
||||
V(zero_string, "0") \
|
||||
V(global_eval_string, "GlobalEval") \
|
||||
V(identity_hash_string, "v8::IdentityHash") \
|
||||
V(closure_string, "(closure)") \
|
||||
V(use_strict_string, "use strict") \
|
||||
V(dot_string, ".") \
|
||||
V(anonymous_function_string, "(anonymous function)") \
|
||||
V(compare_ic_string, "==") \
|
||||
V(strict_compare_ic_string, "===") \
|
||||
V(infinity_string, "Infinity") \
|
||||
|
@ -7626,6 +7626,9 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
|
||||
|
||||
// Parse and allocate variables.
|
||||
CompilationInfo target_info(target, zone());
|
||||
// Use the same AstValueFactory for creating strings in the sub-compilation
|
||||
// step, but don't transfer ownership to target_info.
|
||||
target_info.SetAstValueFactory(top_info()->ast_value_factory(), false);
|
||||
Handle<SharedFunctionInfo> target_shared(target->shared());
|
||||
if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) {
|
||||
if (target_info.isolate()->has_pending_exception()) {
|
||||
|
@ -9,15 +9,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
static bool Match(void* key1, void* key2) {
|
||||
String* name1 = *static_cast<String**>(key1);
|
||||
String* name2 = *static_cast<String**>(key2);
|
||||
ASSERT(name1->IsInternalizedString());
|
||||
ASSERT(name2->IsInternalizedString());
|
||||
return name1 == name2;
|
||||
}
|
||||
|
||||
|
||||
Interface* Interface::Lookup(Handle<String> name, Zone* zone) {
|
||||
ASSERT(IsModule());
|
||||
ZoneHashMap* map = Chase()->exports_;
|
||||
@ -47,8 +38,8 @@ int Nesting::current_ = 0;
|
||||
#endif
|
||||
|
||||
|
||||
void Interface::DoAdd(
|
||||
void* name, uint32_t hash, Interface* interface, Zone* zone, bool* ok) {
|
||||
void Interface::DoAdd(const void* name, uint32_t hash, Interface* interface,
|
||||
Zone* zone, bool* ok) {
|
||||
MakeModule(ok);
|
||||
if (!*ok) return;
|
||||
|
||||
@ -57,8 +48,9 @@ void Interface::DoAdd(
|
||||
PrintF("%*s# Adding...\n", Nesting::current(), "");
|
||||
PrintF("%*sthis = ", Nesting::current(), "");
|
||||
this->Print(Nesting::current());
|
||||
PrintF("%*s%s : ", Nesting::current(), "",
|
||||
(*static_cast<String**>(name))->ToAsciiArray());
|
||||
const AstRawString* symbol = static_cast<const AstRawString*>(name);
|
||||
PrintF("%*s%.*s : ", Nesting::current(), "", symbol->length(),
|
||||
symbol->raw_data());
|
||||
interface->Print(Nesting::current());
|
||||
}
|
||||
#endif
|
||||
@ -68,10 +60,12 @@ void Interface::DoAdd(
|
||||
|
||||
if (*map == NULL) {
|
||||
*map = new(zone->New(sizeof(ZoneHashMap)))
|
||||
ZoneHashMap(Match, ZoneHashMap::kDefaultHashMapCapacity, allocator);
|
||||
ZoneHashMap(ZoneHashMap::PointersMatch,
|
||||
ZoneHashMap::kDefaultHashMapCapacity, allocator);
|
||||
}
|
||||
|
||||
ZoneHashMap::Entry* p = (*map)->Lookup(name, hash, !IsFrozen(), allocator);
|
||||
ZoneHashMap::Entry* p =
|
||||
(*map)->Lookup(const_cast<void*>(name), hash, !IsFrozen(), allocator);
|
||||
if (p == NULL) {
|
||||
// This didn't have name but was frozen already, that's an error.
|
||||
*ok = false;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef V8_INTERFACE_H_
|
||||
#define V8_INTERFACE_H_
|
||||
|
||||
#include "src/ast-value-factory.h"
|
||||
#include "src/zone-inl.h" // For operator new.
|
||||
|
||||
namespace v8 {
|
||||
@ -59,8 +60,9 @@ class Interface : public ZoneObject {
|
||||
|
||||
// Add a name to the list of exports. If it already exists, unify with
|
||||
// interface, otherwise insert unless this is closed.
|
||||
void Add(Handle<String> name, Interface* interface, Zone* zone, bool* ok) {
|
||||
DoAdd(name.location(), name->Hash(), interface, zone, ok);
|
||||
void Add(const AstRawString* name, Interface* interface, Zone* zone,
|
||||
bool* ok) {
|
||||
DoAdd(name, name->hash(), interface, zone, ok);
|
||||
}
|
||||
|
||||
// Unify with another interface. If successful, both interface objects will
|
||||
@ -146,9 +148,9 @@ class Interface : public ZoneObject {
|
||||
class Iterator {
|
||||
public:
|
||||
bool done() const { return entry_ == NULL; }
|
||||
Handle<String> name() const {
|
||||
const AstRawString* name() const {
|
||||
ASSERT(!done());
|
||||
return Handle<String>(*static_cast<String**>(entry_->key));
|
||||
return static_cast<const AstRawString*>(entry_->key);
|
||||
}
|
||||
Interface* interface() const {
|
||||
ASSERT(!done());
|
||||
@ -207,7 +209,7 @@ class Interface : public ZoneObject {
|
||||
return result;
|
||||
}
|
||||
|
||||
void DoAdd(void* name, uint32_t hash, Interface* interface, Zone* zone,
|
||||
void DoAdd(const void* name, uint32_t hash, Interface* interface, Zone* zone,
|
||||
bool* ok);
|
||||
void DoUnify(Interface* that, bool* ok, Zone* zone);
|
||||
};
|
||||
|
@ -1701,22 +1701,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
|
||||
|
||||
|
||||
bool HeapNumber::HeapNumberBooleanValue() {
|
||||
// NaN, +0, and -0 should return the false object
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union IeeeDoubleLittleEndianArchType u;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
union IeeeDoubleBigEndianArchType u;
|
||||
#endif
|
||||
u.d = value();
|
||||
if (u.bits.exp == 2047) {
|
||||
// Detect NaN for IEEE double precision floating point.
|
||||
if ((u.bits.man_low | u.bits.man_high) != 0) return false;
|
||||
}
|
||||
if (u.bits.exp == 0) {
|
||||
// Detect +0, and -0 for IEEE double precision floating point.
|
||||
if ((u.bits.man_low | u.bits.man_high) == 0) return false;
|
||||
}
|
||||
return true;
|
||||
return DoubleToBoolean(value());
|
||||
}
|
||||
|
||||
|
||||
@ -9362,29 +9347,7 @@ bool String::ComputeArrayIndex(uint32_t* index) {
|
||||
if (length == 0 || length > kMaxArrayIndexSize) return false;
|
||||
ConsStringIteratorOp op;
|
||||
StringCharacterStream stream(this, &op);
|
||||
uint16_t ch = stream.GetNext();
|
||||
|
||||
// If the string begins with a '0' character, it must only consist
|
||||
// of it to be a legal array index.
|
||||
if (ch == '0') {
|
||||
*index = 0;
|
||||
return length == 1;
|
||||
}
|
||||
|
||||
// Convert string to uint32 array index; character by character.
|
||||
int d = ch - '0';
|
||||
if (d < 0 || d > 9) return false;
|
||||
uint32_t result = d;
|
||||
while (stream.HasMore()) {
|
||||
d = stream.GetNext() - '0';
|
||||
if (d < 0 || d > 9) return false;
|
||||
// Check that the new result is below the 32 bit limit.
|
||||
if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
|
||||
result = (result * 10) + d;
|
||||
}
|
||||
|
||||
*index = result;
|
||||
return true;
|
||||
return StringToArrayIndex(&stream, index);
|
||||
}
|
||||
|
||||
|
||||
|
476
src/parser.cc
476
src/parser.cc
File diff suppressed because it is too large
Load Diff
121
src/parser.h
121
src/parser.h
@ -389,7 +389,7 @@ class ParserTraits {
|
||||
typedef v8::internal::Zone Zone;
|
||||
|
||||
// Return types for traversing functions.
|
||||
typedef Handle<String> Identifier;
|
||||
typedef const AstRawString* Identifier;
|
||||
typedef v8::internal::Expression* Expression;
|
||||
typedef Yield* YieldExpression;
|
||||
typedef v8::internal::FunctionLiteral* FunctionLiteral;
|
||||
@ -421,29 +421,29 @@ class ParserTraits {
|
||||
}
|
||||
|
||||
// Helper functions for recursive descent.
|
||||
bool IsEvalOrArguments(Handle<String> identifier) const;
|
||||
bool IsEvalOrArguments(const AstRawString* identifier) const;
|
||||
|
||||
// Returns true if the expression is of type "this.foo".
|
||||
static bool IsThisProperty(Expression* expression);
|
||||
|
||||
static bool IsIdentifier(Expression* expression);
|
||||
|
||||
static Handle<String> AsIdentifier(Expression* expression) {
|
||||
static const AstRawString* AsIdentifier(Expression* expression) {
|
||||
ASSERT(IsIdentifier(expression));
|
||||
return expression->AsVariableProxy()->name();
|
||||
return expression->AsVariableProxy()->raw_name();
|
||||
}
|
||||
|
||||
static bool IsBoilerplateProperty(ObjectLiteral::Property* property) {
|
||||
return ObjectLiteral::IsBoilerplateProperty(property);
|
||||
}
|
||||
|
||||
static bool IsArrayIndex(Handle<String> string, uint32_t* index) {
|
||||
return !string.is_null() && string->AsArrayIndex(index);
|
||||
static bool IsArrayIndex(const AstRawString* string, uint32_t* index) {
|
||||
return string->AsArrayIndex(index);
|
||||
}
|
||||
|
||||
// Functions for encapsulating the differences between parsing and preparsing;
|
||||
// operations interleaved with the recursive descent.
|
||||
static void PushLiteralName(FuncNameInferrer* fni, Handle<String> id) {
|
||||
static void PushLiteralName(FuncNameInferrer* fni, const AstRawString* id) {
|
||||
fni->PushLiteralName(id);
|
||||
}
|
||||
void PushPropertyName(FuncNameInferrer* fni, Expression* expression);
|
||||
@ -501,16 +501,17 @@ class ParserTraits {
|
||||
// type. The first argument may be null (in the handle sense) in
|
||||
// which case no arguments are passed to the constructor.
|
||||
Expression* NewThrowSyntaxError(
|
||||
const char* type, Handle<Object> arg, int pos);
|
||||
const char* type, const AstRawString* arg, int pos);
|
||||
|
||||
// Generate AST node that throws a TypeError with the given
|
||||
// type. Both arguments must be non-null (in the handle sense).
|
||||
Expression* NewThrowTypeError(const char* type, Handle<Object> arg, int pos);
|
||||
Expression* NewThrowTypeError(const char* type, const AstRawString* arg,
|
||||
int pos);
|
||||
|
||||
// Generic AST generator for throwing errors from compiled code.
|
||||
Expression* NewThrowError(
|
||||
Handle<String> constructor, const char* type,
|
||||
Vector<Handle<Object> > arguments, int pos);
|
||||
const AstRawString* constructor, const char* type,
|
||||
const AstRawString* arg, int pos);
|
||||
|
||||
// Reporting errors.
|
||||
void ReportMessageAt(Scanner::Location source_location,
|
||||
@ -518,16 +519,19 @@ class ParserTraits {
|
||||
const char* arg = NULL,
|
||||
bool is_reference_error = false);
|
||||
void ReportMessage(const char* message,
|
||||
MaybeHandle<String> arg,
|
||||
const char* arg = NULL,
|
||||
bool is_reference_error = false);
|
||||
void ReportMessage(const char* message,
|
||||
const AstRawString* arg,
|
||||
bool is_reference_error = false);
|
||||
void ReportMessageAt(Scanner::Location source_location,
|
||||
const char* message,
|
||||
MaybeHandle<String> arg,
|
||||
const AstRawString* arg,
|
||||
bool is_reference_error = false);
|
||||
|
||||
// "null" return type creators.
|
||||
static Handle<String> EmptyIdentifier() {
|
||||
return Handle<String>();
|
||||
static const AstRawString* EmptyIdentifier() {
|
||||
return NULL;
|
||||
}
|
||||
static Expression* EmptyExpression() {
|
||||
return NULL;
|
||||
@ -545,16 +549,16 @@ class ParserTraits {
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
|
||||
// Producing data during the recursive descent.
|
||||
Handle<String> GetSymbol(Scanner* scanner = NULL);
|
||||
Handle<String> NextLiteralString(Scanner* scanner,
|
||||
PretenureFlag tenured);
|
||||
const AstRawString* GetSymbol(Scanner* scanner);
|
||||
const AstRawString* GetNextSymbol(Scanner* scanner);
|
||||
|
||||
Expression* ThisExpression(Scope* scope,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
Literal* ExpressionFromLiteral(
|
||||
Token::Value token, int pos, Scanner* scanner,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
Expression* ExpressionFromIdentifier(
|
||||
Handle<String> name, int pos, Scope* scope,
|
||||
const AstRawString* name, int pos, Scope* scope,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
Expression* ExpressionFromString(
|
||||
int pos, Scanner* scanner,
|
||||
@ -572,7 +576,7 @@ class ParserTraits {
|
||||
// Temporary glue; these functions will move to ParserBase.
|
||||
Expression* ParseV8Intrinsic(bool* ok);
|
||||
FunctionLiteral* ParseFunctionLiteral(
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
Scanner::Location function_name_location,
|
||||
bool name_is_strict_reserved,
|
||||
bool is_generator,
|
||||
@ -644,7 +648,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
Handle<String> source);
|
||||
|
||||
// Report syntax error
|
||||
void ReportInvalidCachedData(Handle<String> name, bool* ok);
|
||||
void ReportInvalidCachedData(const AstRawString* name, bool* ok);
|
||||
|
||||
void SetCachedData(ScriptData** data,
|
||||
CachedDataMode cached_data_mode) {
|
||||
@ -671,8 +675,10 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
// for failure at the call sites.
|
||||
void* ParseSourceElements(ZoneList<Statement*>* processor, int end_token,
|
||||
bool is_eval, bool is_global, bool* ok);
|
||||
Statement* ParseModuleElement(ZoneStringList* labels, bool* ok);
|
||||
Statement* ParseModuleDeclaration(ZoneStringList* names, bool* ok);
|
||||
Statement* ParseModuleElement(ZoneList<const AstRawString*>* labels,
|
||||
bool* ok);
|
||||
Statement* ParseModuleDeclaration(ZoneList<const AstRawString*>* names,
|
||||
bool* ok);
|
||||
Module* ParseModule(bool* ok);
|
||||
Module* ParseModuleLiteral(bool* ok);
|
||||
Module* ParseModulePath(bool* ok);
|
||||
@ -681,38 +687,45 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
Module* ParseModuleSpecifier(bool* ok);
|
||||
Block* ParseImportDeclaration(bool* ok);
|
||||
Statement* ParseExportDeclaration(bool* ok);
|
||||
Statement* ParseBlockElement(ZoneStringList* labels, bool* ok);
|
||||
Statement* ParseStatement(ZoneStringList* labels, bool* ok);
|
||||
Statement* ParseFunctionDeclaration(ZoneStringList* names, bool* ok);
|
||||
Statement* ParseBlockElement(ZoneList<const AstRawString*>* labels, bool* ok);
|
||||
Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
|
||||
Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
|
||||
bool* ok);
|
||||
Statement* ParseNativeDeclaration(bool* ok);
|
||||
Block* ParseBlock(ZoneStringList* labels, bool* ok);
|
||||
Block* ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok);
|
||||
Block* ParseVariableStatement(VariableDeclarationContext var_context,
|
||||
ZoneStringList* names,
|
||||
ZoneList<const AstRawString*>* names,
|
||||
bool* ok);
|
||||
Block* ParseVariableDeclarations(VariableDeclarationContext var_context,
|
||||
VariableDeclarationProperties* decl_props,
|
||||
ZoneStringList* names,
|
||||
Handle<String>* out,
|
||||
ZoneList<const AstRawString*>* names,
|
||||
const AstRawString** out,
|
||||
bool* ok);
|
||||
Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels,
|
||||
Statement* ParseExpressionOrLabelledStatement(
|
||||
ZoneList<const AstRawString*>* labels, bool* ok);
|
||||
IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels,
|
||||
bool* ok);
|
||||
IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok);
|
||||
Statement* ParseContinueStatement(bool* ok);
|
||||
Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok);
|
||||
Statement* ParseBreakStatement(ZoneList<const AstRawString*>* labels,
|
||||
bool* ok);
|
||||
Statement* ParseReturnStatement(bool* ok);
|
||||
Statement* ParseWithStatement(ZoneStringList* labels, bool* ok);
|
||||
Statement* ParseWithStatement(ZoneList<const AstRawString*>* labels,
|
||||
bool* ok);
|
||||
CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
|
||||
SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok);
|
||||
DoWhileStatement* ParseDoWhileStatement(ZoneStringList* labels, bool* ok);
|
||||
WhileStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok);
|
||||
Statement* ParseForStatement(ZoneStringList* labels, bool* ok);
|
||||
SwitchStatement* ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
|
||||
bool* ok);
|
||||
DoWhileStatement* ParseDoWhileStatement(ZoneList<const AstRawString*>* labels,
|
||||
bool* ok);
|
||||
WhileStatement* ParseWhileStatement(ZoneList<const AstRawString*>* labels,
|
||||
bool* ok);
|
||||
Statement* ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
|
||||
Statement* ParseThrowStatement(bool* ok);
|
||||
Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
|
||||
TryStatement* ParseTryStatement(bool* ok);
|
||||
DebuggerStatement* ParseDebuggerStatement(bool* ok);
|
||||
|
||||
// Support for hamony block scoped bindings.
|
||||
Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
|
||||
Block* ParseScopedBlock(ZoneList<const AstRawString*>* labels, bool* ok);
|
||||
|
||||
// Initialize the components of a for-in / for-of statement.
|
||||
void InitializeForEachStatement(ForEachStatement* stmt,
|
||||
@ -720,12 +733,12 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
Expression* subject,
|
||||
Statement* body);
|
||||
Statement* DesugarLetBindingsInForStatement(
|
||||
Scope* inner_scope, ZoneStringList* names, ForStatement* loop,
|
||||
Statement* init, Expression* cond, Statement* next, Statement* body,
|
||||
bool* ok);
|
||||
Scope* inner_scope, ZoneList<const AstRawString*>* names,
|
||||
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
|
||||
Statement* body, bool* ok);
|
||||
|
||||
FunctionLiteral* ParseFunctionLiteral(
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
Scanner::Location function_name_location,
|
||||
bool name_is_strict_reserved,
|
||||
bool is_generator,
|
||||
@ -754,14 +767,14 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
void CheckConflictingVarDeclarations(Scope* scope, bool* ok);
|
||||
|
||||
// Parser support
|
||||
VariableProxy* NewUnresolved(Handle<String> name,
|
||||
VariableProxy* NewUnresolved(const AstRawString* name,
|
||||
VariableMode mode,
|
||||
Interface* interface);
|
||||
void Declare(Declaration* declaration, bool resolve, bool* ok);
|
||||
|
||||
bool TargetStackContainsLabel(Handle<String> label);
|
||||
BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok);
|
||||
IterationStatement* LookupContinueTarget(Handle<String> label, bool* ok);
|
||||
bool TargetStackContainsLabel(const AstRawString* label);
|
||||
BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
|
||||
IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
|
||||
|
||||
void RegisterTargetUse(Label* target, Target* stop);
|
||||
|
||||
@ -771,7 +784,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
|
||||
// Skip over a lazy function, either using cached data if we have it, or
|
||||
// by parsing the function with PreParser. Consumes the ending }.
|
||||
void SkipLazyFunctionBody(Handle<String> function_name,
|
||||
void SkipLazyFunctionBody(const AstRawString* function_name,
|
||||
int* materialized_literal_count,
|
||||
int* expected_property_count,
|
||||
bool* ok);
|
||||
@ -780,12 +793,9 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
SingletonLogger* logger);
|
||||
|
||||
// Consumes the ending }.
|
||||
ZoneList<Statement*>* ParseEagerFunctionBody(Handle<String> function_name,
|
||||
int pos,
|
||||
Variable* fvar,
|
||||
Token::Value fvar_init_op,
|
||||
bool is_generator,
|
||||
bool* ok);
|
||||
ZoneList<Statement*>* ParseEagerFunctionBody(
|
||||
const AstRawString* function_name, int pos, Variable* fvar,
|
||||
Token::Value fvar_init_op, bool is_generator, bool* ok);
|
||||
|
||||
void ThrowPendingError();
|
||||
|
||||
@ -798,6 +808,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
Target* target_stack_; // for break, continue statements
|
||||
ScriptData** cached_data_;
|
||||
CachedDataMode cached_data_mode_;
|
||||
AstValueFactory* ast_value_factory_;
|
||||
|
||||
CompilationInfo* info_;
|
||||
|
||||
@ -805,7 +816,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
bool has_pending_error_;
|
||||
Scanner::Location pending_error_location_;
|
||||
const char* pending_error_message_;
|
||||
MaybeHandle<String> pending_error_arg_;
|
||||
const AstRawString* pending_error_arg_;
|
||||
const char* pending_error_char_arg_;
|
||||
bool pending_error_is_reference_error_;
|
||||
};
|
||||
|
@ -150,7 +150,8 @@ class ParserBase : public Traits {
|
||||
FunctionState** function_state_stack,
|
||||
typename Traits::Type::Scope** scope_stack,
|
||||
typename Traits::Type::Scope* scope,
|
||||
typename Traits::Type::Zone* zone = NULL);
|
||||
typename Traits::Type::Zone* zone = NULL,
|
||||
AstValueFactory* ast_value_factory = NULL);
|
||||
~FunctionState();
|
||||
|
||||
int NextMaterializedLiteralIndex() {
|
||||
@ -395,7 +396,9 @@ class ParserBase : public Traits {
|
||||
|
||||
void ReportMessageAt(Scanner::Location location, const char* message,
|
||||
bool is_reference_error = false) {
|
||||
Traits::ReportMessageAt(location, message, NULL, is_reference_error);
|
||||
Traits::ReportMessageAt(location, message,
|
||||
reinterpret_cast<const char*>(NULL),
|
||||
is_reference_error);
|
||||
}
|
||||
|
||||
void ReportUnexpectedToken(Token::Value token);
|
||||
@ -782,8 +785,8 @@ class PreParserScope {
|
||||
|
||||
class PreParserFactory {
|
||||
public:
|
||||
explicit PreParserFactory(void* extra_param) {}
|
||||
PreParserExpression NewLiteral(PreParserIdentifier identifier,
|
||||
explicit PreParserFactory(void* extra_param1, void* extra_param2) {}
|
||||
PreParserExpression NewStringLiteral(PreParserIdentifier identifier,
|
||||
int pos) {
|
||||
return PreParserExpression::Default();
|
||||
}
|
||||
@ -1036,8 +1039,8 @@ class PreParserTraits {
|
||||
|
||||
// Producing data during the recursive descent.
|
||||
PreParserIdentifier GetSymbol(Scanner* scanner);
|
||||
static PreParserIdentifier NextLiteralString(Scanner* scanner,
|
||||
PretenureFlag tenured) {
|
||||
|
||||
static PreParserIdentifier GetNextSymbol(Scanner* scanner) {
|
||||
return PreParserIdentifier::Default();
|
||||
}
|
||||
|
||||
@ -1225,7 +1228,8 @@ ParserBase<Traits>::FunctionState::FunctionState(
|
||||
FunctionState** function_state_stack,
|
||||
typename Traits::Type::Scope** scope_stack,
|
||||
typename Traits::Type::Scope* scope,
|
||||
typename Traits::Type::Zone* extra_param)
|
||||
typename Traits::Type::Zone* extra_param,
|
||||
AstValueFactory* ast_value_factory)
|
||||
: next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize),
|
||||
next_handler_index_(0),
|
||||
expected_property_count_(0),
|
||||
@ -1237,7 +1241,7 @@ ParserBase<Traits>::FunctionState::FunctionState(
|
||||
outer_scope_(*scope_stack),
|
||||
saved_ast_node_id_(0),
|
||||
extra_param_(extra_param),
|
||||
factory_(extra_param) {
|
||||
factory_(extra_param, ast_value_factory) {
|
||||
*scope_stack_ = scope;
|
||||
*function_state_stack = this;
|
||||
Traits::SetUpFunctionState(this, extra_param);
|
||||
@ -1363,14 +1367,14 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseRegExpLiteral(
|
||||
|
||||
int literal_index = function_state_->NextMaterializedLiteralIndex();
|
||||
|
||||
IdentifierT js_pattern = this->NextLiteralString(scanner(), TENURED);
|
||||
IdentifierT js_pattern = this->GetNextSymbol(scanner());
|
||||
if (!scanner()->ScanRegExpFlags()) {
|
||||
Next();
|
||||
ReportMessage("invalid_regexp_flags");
|
||||
*ok = false;
|
||||
return Traits::EmptyExpression();
|
||||
}
|
||||
IdentifierT js_flags = this->NextLiteralString(scanner(), TENURED);
|
||||
IdentifierT js_flags = this->GetNextSymbol(scanner());
|
||||
Next();
|
||||
return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index, pos);
|
||||
}
|
||||
@ -1615,7 +1619,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
||||
}
|
||||
// Failed to parse as get/set property, so it's just a normal property
|
||||
// (which might be called "get" or "set" or something else).
|
||||
key = factory()->NewLiteral(id, next_pos);
|
||||
key = factory()->NewStringLiteral(id, next_pos);
|
||||
break;
|
||||
}
|
||||
case Token::STRING: {
|
||||
@ -1627,7 +1631,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
||||
key = factory()->NewNumberLiteral(index, next_pos);
|
||||
break;
|
||||
}
|
||||
key = factory()->NewLiteral(string, next_pos);
|
||||
key = factory()->NewStringLiteral(string, next_pos);
|
||||
break;
|
||||
}
|
||||
case Token::NUMBER: {
|
||||
@ -1640,7 +1644,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
||||
if (Token::IsKeyword(next)) {
|
||||
Consume(next);
|
||||
IdentifierT string = this->GetSymbol(scanner_);
|
||||
key = factory()->NewLiteral(string, next_pos);
|
||||
key = factory()->NewStringLiteral(string, next_pos);
|
||||
} else {
|
||||
Token::Value next = Next();
|
||||
ReportUnexpectedToken(next);
|
||||
@ -2009,7 +2013,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) {
|
||||
int pos = position();
|
||||
IdentifierT name = ParseIdentifierName(CHECK_OK);
|
||||
result = factory()->NewProperty(
|
||||
result, factory()->NewLiteral(name, pos), pos);
|
||||
result, factory()->NewStringLiteral(name, pos), pos);
|
||||
if (fni_ != NULL) this->PushLiteralName(fni_, name);
|
||||
break;
|
||||
}
|
||||
@ -2132,7 +2136,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression,
|
||||
int pos = position();
|
||||
IdentifierT name = ParseIdentifierName(CHECK_OK);
|
||||
expression = factory()->NewProperty(
|
||||
expression, factory()->NewLiteral(name, pos), pos);
|
||||
expression, factory()->NewStringLiteral(name, pos), pos);
|
||||
if (fni_ != NULL) {
|
||||
this->PushLiteralName(fni_, name);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/ast-value-factory.h"
|
||||
#include "src/platform.h"
|
||||
#include "src/prettyprinter.h"
|
||||
#include "src/scopes.h"
|
||||
@ -133,7 +134,7 @@ void PrettyPrinter::VisitIfStatement(IfStatement* node) {
|
||||
|
||||
void PrettyPrinter::VisitContinueStatement(ContinueStatement* node) {
|
||||
Print("continue");
|
||||
ZoneStringList* labels = node->target()->labels();
|
||||
ZoneList<const AstRawString*>* labels = node->target()->labels();
|
||||
if (labels != NULL) {
|
||||
Print(" ");
|
||||
ASSERT(labels->length() > 0); // guaranteed to have at least one entry
|
||||
@ -145,7 +146,7 @@ void PrettyPrinter::VisitContinueStatement(ContinueStatement* node) {
|
||||
|
||||
void PrettyPrinter::VisitBreakStatement(BreakStatement* node) {
|
||||
Print("break");
|
||||
ZoneStringList* labels = node->target()->labels();
|
||||
ZoneList<const AstRawString*>* labels = node->target()->labels();
|
||||
if (labels != NULL) {
|
||||
Print(" ");
|
||||
ASSERT(labels->length() > 0); // guaranteed to have at least one entry
|
||||
@ -524,7 +525,7 @@ void PrettyPrinter::PrintStatements(ZoneList<Statement*>* statements) {
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::PrintLabels(ZoneStringList* labels) {
|
||||
void PrettyPrinter::PrintLabels(ZoneList<const AstRawString*>* labels) {
|
||||
if (labels != NULL) {
|
||||
for (int i = 0; i < labels->length(); i++) {
|
||||
PrintLiteral(labels->at(i), false);
|
||||
@ -582,6 +583,11 @@ void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) {
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::PrintLiteral(const AstRawString* value, bool quote) {
|
||||
PrintLiteral(value->string(), quote);
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::PrintParameters(Scope* scope) {
|
||||
Print("(");
|
||||
for (int i = 0; i < scope->num_parameters(); i++) {
|
||||
@ -676,7 +682,7 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
|
||||
}
|
||||
|
||||
|
||||
void AstPrinter::PrintLabelsIndented(ZoneStringList* labels) {
|
||||
void AstPrinter::PrintLabelsIndented(ZoneList<const AstRawString*>* labels) {
|
||||
if (labels == NULL || labels->length() == 0) return;
|
||||
PrintIndented("LABELS ");
|
||||
PrintLabels(labels);
|
||||
|
@ -44,9 +44,10 @@ class PrettyPrinter: public AstVisitor {
|
||||
const char* Output() const { return output_; }
|
||||
|
||||
virtual void PrintStatements(ZoneList<Statement*>* statements);
|
||||
void PrintLabels(ZoneStringList* labels);
|
||||
void PrintLabels(ZoneList<const AstRawString*>* labels);
|
||||
virtual void PrintArguments(ZoneList<Expression*>* arguments);
|
||||
void PrintLiteral(Handle<Object> value, bool quote);
|
||||
void PrintLiteral(const AstRawString* value, bool quote);
|
||||
void PrintParameters(Scope* scope);
|
||||
void PrintDeclarations(ZoneList<Declaration*>* declarations);
|
||||
void PrintFunctionLiteral(FunctionLiteral* function);
|
||||
@ -83,7 +84,7 @@ class AstPrinter: public PrettyPrinter {
|
||||
void PrintLiteralWithModeIndented(const char* info,
|
||||
Variable* var,
|
||||
Handle<Object> value);
|
||||
void PrintLabelsIndented(ZoneStringList* labels);
|
||||
void PrintLabelsIndented(ZoneList<const AstRawString*>* labels);
|
||||
|
||||
void inc_indent() { indent_++; }
|
||||
void dec_indent() { indent_--; }
|
||||
|
@ -20,7 +20,9 @@ class Processor: public AstVisitor {
|
||||
result_assigned_(false),
|
||||
is_set_(false),
|
||||
in_try_(false),
|
||||
factory_(zone) {
|
||||
// Passing a null AstValueFactory is fine, because Processor doesn't
|
||||
// need to create strings or literals.
|
||||
factory_(zone, NULL) {
|
||||
InitializeAstVisitor(zone);
|
||||
}
|
||||
|
||||
@ -234,8 +236,10 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
|
||||
|
||||
ZoneList<Statement*>* body = function->body();
|
||||
if (!body->is_empty()) {
|
||||
Variable* result = scope->NewTemporary(
|
||||
info->isolate()->factory()->dot_result_string());
|
||||
Variable* result =
|
||||
scope->NewTemporary(info->ast_value_factory()->dot_result_string());
|
||||
// The name string must be internalized at this point.
|
||||
ASSERT(!result->name().is_null());
|
||||
Processor processor(result, info->zone());
|
||||
processor.Process(body);
|
||||
if (processor.HasStackOverflow()) return false;
|
||||
@ -250,7 +254,7 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
|
||||
// coincides with the end of the with scope which is the position of '1'.
|
||||
int pos = function->end_position();
|
||||
VariableProxy* result_proxy = processor.factory()->NewVariableProxy(
|
||||
result->name(), false, result->interface(), pos);
|
||||
result->raw_name(), false, result->interface(), pos);
|
||||
result_proxy->BindTo(result);
|
||||
Statement* result_statement =
|
||||
processor.factory()->NewReturnStatement(result_proxy, pos);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "include/v8stdint.h"
|
||||
#include "src/ast-value-factory.h"
|
||||
#include "src/char-predicates-inl.h"
|
||||
#include "src/conversions-inl.h"
|
||||
#include "src/list-inl.h"
|
||||
@ -1093,26 +1094,19 @@ bool Scanner::ScanRegExpFlags() {
|
||||
}
|
||||
|
||||
|
||||
Handle<String> Scanner::AllocateNextLiteralString(Isolate* isolate,
|
||||
PretenureFlag tenured) {
|
||||
if (is_next_literal_one_byte()) {
|
||||
return isolate->factory()->NewStringFromOneByte(
|
||||
next_literal_one_byte_string(), tenured).ToHandleChecked();
|
||||
} else {
|
||||
return isolate->factory()->NewStringFromTwoByte(
|
||||
next_literal_two_byte_string(), tenured).ToHandleChecked();
|
||||
const AstRawString* Scanner::CurrentSymbol(AstValueFactory* ast_value_factory) {
|
||||
if (is_literal_one_byte()) {
|
||||
return ast_value_factory->GetOneByteString(literal_one_byte_string());
|
||||
}
|
||||
return ast_value_factory->GetTwoByteString(literal_two_byte_string());
|
||||
}
|
||||
|
||||
|
||||
Handle<String> Scanner::AllocateInternalizedString(Isolate* isolate) {
|
||||
if (is_literal_one_byte()) {
|
||||
return isolate->factory()->InternalizeOneByteString(
|
||||
literal_one_byte_string());
|
||||
} else {
|
||||
return isolate->factory()->InternalizeTwoByteString(
|
||||
literal_two_byte_string());
|
||||
const AstRawString* Scanner::NextSymbol(AstValueFactory* ast_value_factory) {
|
||||
if (is_next_literal_one_byte()) {
|
||||
return ast_value_factory->GetOneByteString(next_literal_one_byte_string());
|
||||
}
|
||||
return ast_value_factory->GetTwoByteString(next_literal_two_byte_string());
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,6 +21,8 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
class AstRawString;
|
||||
class AstValueFactory;
|
||||
class ParserRecorder;
|
||||
|
||||
|
||||
@ -376,9 +378,8 @@ class Scanner {
|
||||
return next_.literal_chars->is_contextual_keyword(keyword);
|
||||
}
|
||||
|
||||
Handle<String> AllocateNextLiteralString(Isolate* isolate,
|
||||
PretenureFlag tenured);
|
||||
Handle<String> AllocateInternalizedString(Isolate* isolate);
|
||||
const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory);
|
||||
const AstRawString* NextSymbol(AstValueFactory* ast_value_factory);
|
||||
|
||||
double DoubleValue();
|
||||
bool UnescapedLiteralMatches(const char* data, int length) {
|
||||
|
@ -540,7 +540,7 @@ Handle<ModuleInfo> ModuleInfo::Create(
|
||||
for (Interface::Iterator it = interface->iterator();
|
||||
!it.done(); it.Advance(), ++i) {
|
||||
Variable* var = scope->LookupLocal(it.name());
|
||||
info->set_name(i, *it.name());
|
||||
info->set_name(i, *(it.name()->string()));
|
||||
info->set_mode(i, var->mode());
|
||||
ASSERT((var->mode() == MODULE) == (it.interface()->IsModule()));
|
||||
if (var->mode() == MODULE) {
|
||||
|
142
src/scopes.cc
142
src/scopes.cc
@ -24,34 +24,28 @@ namespace internal {
|
||||
// use. Because a Variable holding a handle with the same location exists
|
||||
// this is ensured.
|
||||
|
||||
static bool Match(void* key1, void* key2) {
|
||||
String* name1 = *reinterpret_cast<String**>(key1);
|
||||
String* name2 = *reinterpret_cast<String**>(key2);
|
||||
ASSERT(name1->IsInternalizedString());
|
||||
ASSERT(name2->IsInternalizedString());
|
||||
return name1 == name2;
|
||||
}
|
||||
|
||||
|
||||
VariableMap::VariableMap(Zone* zone)
|
||||
: ZoneHashMap(Match, 8, ZoneAllocationPolicy(zone)),
|
||||
: ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
|
||||
zone_(zone) {}
|
||||
VariableMap::~VariableMap() {}
|
||||
|
||||
|
||||
Variable* VariableMap::Declare(
|
||||
Scope* scope,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
VariableMode mode,
|
||||
bool is_valid_lhs,
|
||||
Variable::Kind kind,
|
||||
InitializationFlag initialization_flag,
|
||||
Interface* interface) {
|
||||
Entry* p = ZoneHashMap::Lookup(name.location(), name->Hash(), true,
|
||||
ZoneAllocationPolicy(zone()));
|
||||
// AstRawStrings are unambiguous, i.e., the same string is always represented
|
||||
// by the same AstRawString*.
|
||||
// FIXME(marja): fix the type of Lookup.
|
||||
Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(),
|
||||
true, ZoneAllocationPolicy(zone()));
|
||||
if (p->value == NULL) {
|
||||
// The variable has not been declared yet -> insert it.
|
||||
ASSERT(p->key == name.location());
|
||||
ASSERT(p->key == name);
|
||||
p->value = new(zone()) Variable(scope,
|
||||
name,
|
||||
mode,
|
||||
@ -64,11 +58,11 @@ Variable* VariableMap::Declare(
|
||||
}
|
||||
|
||||
|
||||
Variable* VariableMap::Lookup(Handle<String> name) {
|
||||
Entry* p = ZoneHashMap::Lookup(name.location(), name->Hash(), false,
|
||||
ZoneAllocationPolicy(NULL));
|
||||
Variable* VariableMap::Lookup(const AstRawString* name) {
|
||||
Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(),
|
||||
false, ZoneAllocationPolicy(NULL));
|
||||
if (p != NULL) {
|
||||
ASSERT(*reinterpret_cast<String**>(p->key) == *name);
|
||||
ASSERT(reinterpret_cast<const AstRawString*>(p->key) == name);
|
||||
ASSERT(p->value != NULL);
|
||||
return reinterpret_cast<Variable*>(p->value);
|
||||
}
|
||||
@ -79,7 +73,8 @@ Variable* VariableMap::Lookup(Handle<String> name) {
|
||||
// ----------------------------------------------------------------------------
|
||||
// Implementation of Scope
|
||||
|
||||
Scope::Scope(Scope* outer_scope, ScopeType scope_type, Zone* zone)
|
||||
Scope::Scope(Scope* outer_scope, ScopeType scope_type,
|
||||
AstValueFactory* ast_value_factory, Zone* zone)
|
||||
: isolate_(zone->isolate()),
|
||||
inner_scopes_(4, zone),
|
||||
variables_(zone),
|
||||
@ -92,6 +87,7 @@ Scope::Scope(Scope* outer_scope, ScopeType scope_type, Zone* zone)
|
||||
(scope_type == MODULE_SCOPE || scope_type == GLOBAL_SCOPE)
|
||||
? Interface::NewModule(zone) : NULL),
|
||||
already_resolved_(false),
|
||||
ast_value_factory_(ast_value_factory),
|
||||
zone_(zone) {
|
||||
SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null());
|
||||
// The outermost scope must be a global scope.
|
||||
@ -103,6 +99,7 @@ Scope::Scope(Scope* outer_scope, ScopeType scope_type, Zone* zone)
|
||||
Scope::Scope(Scope* inner_scope,
|
||||
ScopeType scope_type,
|
||||
Handle<ScopeInfo> scope_info,
|
||||
AstValueFactory* value_factory,
|
||||
Zone* zone)
|
||||
: isolate_(zone->isolate()),
|
||||
inner_scopes_(4, zone),
|
||||
@ -114,6 +111,7 @@ Scope::Scope(Scope* inner_scope,
|
||||
decls_(4, zone),
|
||||
interface_(NULL),
|
||||
already_resolved_(true),
|
||||
ast_value_factory_(value_factory),
|
||||
zone_(zone) {
|
||||
SetDefaults(scope_type, NULL, scope_info);
|
||||
if (!scope_info.is_null()) {
|
||||
@ -126,7 +124,8 @@ Scope::Scope(Scope* inner_scope,
|
||||
}
|
||||
|
||||
|
||||
Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name, Zone* zone)
|
||||
Scope::Scope(Scope* inner_scope, const AstRawString* catch_variable_name,
|
||||
AstValueFactory* value_factory, Zone* zone)
|
||||
: isolate_(zone->isolate()),
|
||||
inner_scopes_(1, zone),
|
||||
variables_(zone),
|
||||
@ -137,6 +136,7 @@ Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name, Zone* zone)
|
||||
decls_(0, zone),
|
||||
interface_(NULL),
|
||||
already_resolved_(true),
|
||||
ast_value_factory_(value_factory),
|
||||
zone_(zone) {
|
||||
SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
|
||||
AddInnerScope(inner_scope);
|
||||
@ -157,7 +157,7 @@ void Scope::SetDefaults(ScopeType scope_type,
|
||||
Handle<ScopeInfo> scope_info) {
|
||||
outer_scope_ = outer_scope;
|
||||
scope_type_ = scope_type;
|
||||
scope_name_ = isolate_->factory()->empty_string();
|
||||
scope_name_ = ast_value_factory_->empty_string();
|
||||
dynamics_ = NULL;
|
||||
receiver_ = NULL;
|
||||
function_ = NULL;
|
||||
@ -199,6 +199,7 @@ Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope,
|
||||
Scope* with_scope = new(zone) Scope(current_scope,
|
||||
WITH_SCOPE,
|
||||
Handle<ScopeInfo>::null(),
|
||||
global_scope->ast_value_factory_,
|
||||
zone);
|
||||
current_scope = with_scope;
|
||||
// All the inner scopes are inside a with.
|
||||
@ -211,30 +212,36 @@ Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope,
|
||||
current_scope = new(zone) Scope(current_scope,
|
||||
GLOBAL_SCOPE,
|
||||
Handle<ScopeInfo>(scope_info),
|
||||
global_scope->ast_value_factory_,
|
||||
zone);
|
||||
} else if (context->IsModuleContext()) {
|
||||
ScopeInfo* scope_info = ScopeInfo::cast(context->module()->scope_info());
|
||||
current_scope = new(zone) Scope(current_scope,
|
||||
MODULE_SCOPE,
|
||||
Handle<ScopeInfo>(scope_info),
|
||||
global_scope->ast_value_factory_,
|
||||
zone);
|
||||
} else if (context->IsFunctionContext()) {
|
||||
ScopeInfo* scope_info = context->closure()->shared()->scope_info();
|
||||
current_scope = new(zone) Scope(current_scope,
|
||||
FUNCTION_SCOPE,
|
||||
Handle<ScopeInfo>(scope_info),
|
||||
global_scope->ast_value_factory_,
|
||||
zone);
|
||||
} else if (context->IsBlockContext()) {
|
||||
ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
|
||||
current_scope = new(zone) Scope(current_scope,
|
||||
BLOCK_SCOPE,
|
||||
Handle<ScopeInfo>(scope_info),
|
||||
global_scope->ast_value_factory_,
|
||||
zone);
|
||||
} else {
|
||||
ASSERT(context->IsCatchContext());
|
||||
String* name = String::cast(context->extension());
|
||||
current_scope = new(zone) Scope(
|
||||
current_scope, Handle<String>(name), zone);
|
||||
current_scope = new (zone) Scope(
|
||||
current_scope,
|
||||
global_scope->ast_value_factory_->GetString(Handle<String>(name)),
|
||||
global_scope->ast_value_factory_, zone);
|
||||
}
|
||||
if (contains_with) current_scope->RecordWithStatement();
|
||||
if (innermost_scope == NULL) innermost_scope = current_scope;
|
||||
@ -266,7 +273,9 @@ bool Scope::Analyze(CompilationInfo* info) {
|
||||
|
||||
// Allocate the variables.
|
||||
{
|
||||
AstNodeFactory<AstNullVisitor> ast_node_factory(info->zone());
|
||||
// Passing NULL as AstValueFactory is ok, because AllocateVariables doesn't
|
||||
// need to create new strings or values.
|
||||
AstNodeFactory<AstNullVisitor> ast_node_factory(info->zone(), NULL);
|
||||
if (!top->AllocateVariables(info, &ast_node_factory)) return false;
|
||||
}
|
||||
|
||||
@ -310,7 +319,7 @@ void Scope::Initialize() {
|
||||
if (is_declaration_scope()) {
|
||||
Variable* var =
|
||||
variables_.Declare(this,
|
||||
isolate_->factory()->this_string(),
|
||||
ast_value_factory_->this_string(),
|
||||
VAR,
|
||||
false,
|
||||
Variable::THIS,
|
||||
@ -327,7 +336,7 @@ void Scope::Initialize() {
|
||||
// Note that it might never be accessed, in which case it won't be
|
||||
// allocated during variable allocation.
|
||||
variables_.Declare(this,
|
||||
isolate_->factory()->arguments_string(),
|
||||
ast_value_factory_->arguments_string(),
|
||||
VAR,
|
||||
true,
|
||||
Variable::ARGUMENTS,
|
||||
@ -366,23 +375,28 @@ Scope* Scope::FinalizeBlockScope() {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::LookupLocal(Handle<String> name) {
|
||||
Variable* Scope::LookupLocal(const AstRawString* name) {
|
||||
Variable* result = variables_.Lookup(name);
|
||||
if (result != NULL || scope_info_.is_null()) {
|
||||
return result;
|
||||
}
|
||||
// The Scope is backed up by ScopeInfo. This means it cannot operate in a
|
||||
// heap-independent mode, and all strings must be internalized immediately. So
|
||||
// it's ok to get the Handle<String> here.
|
||||
Handle<String> name_handle = name->string();
|
||||
// If we have a serialized scope info, we might find the variable there.
|
||||
// There should be no local slot with the given name.
|
||||
ASSERT(scope_info_->StackSlotIndex(*name) < 0);
|
||||
ASSERT(scope_info_->StackSlotIndex(*name_handle) < 0);
|
||||
|
||||
// Check context slot lookup.
|
||||
VariableMode mode;
|
||||
Variable::Location location = Variable::CONTEXT;
|
||||
InitializationFlag init_flag;
|
||||
int index = ScopeInfo::ContextSlotIndex(scope_info_, name, &mode, &init_flag);
|
||||
int index =
|
||||
ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode, &init_flag);
|
||||
if (index < 0) {
|
||||
// Check parameters.
|
||||
index = scope_info_->ParameterIndex(*name);
|
||||
index = scope_info_->ParameterIndex(*name_handle);
|
||||
if (index < 0) return NULL;
|
||||
|
||||
mode = DYNAMIC;
|
||||
@ -397,14 +411,14 @@ Variable* Scope::LookupLocal(Handle<String> name) {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::LookupFunctionVar(Handle<String> name,
|
||||
Variable* Scope::LookupFunctionVar(const AstRawString* name,
|
||||
AstNodeFactory<AstNullVisitor>* factory) {
|
||||
if (function_ != NULL && function_->proxy()->name().is_identical_to(name)) {
|
||||
if (function_ != NULL && function_->proxy()->raw_name() == name) {
|
||||
return function_->proxy()->var();
|
||||
} else if (!scope_info_.is_null()) {
|
||||
// If we are backed by a scope info, try to lookup the variable there.
|
||||
VariableMode mode;
|
||||
int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
|
||||
int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
|
||||
if (index < 0) return NULL;
|
||||
Variable* var = new(zone()) Variable(
|
||||
this, name, mode, true /* is valid LHS */,
|
||||
@ -421,7 +435,7 @@ Variable* Scope::LookupFunctionVar(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::Lookup(Handle<String> name) {
|
||||
Variable* Scope::Lookup(const AstRawString* name) {
|
||||
for (Scope* scope = this;
|
||||
scope != NULL;
|
||||
scope = scope->outer_scope()) {
|
||||
@ -432,7 +446,7 @@ Variable* Scope::Lookup(Handle<String> name) {
|
||||
}
|
||||
|
||||
|
||||
void Scope::DeclareParameter(Handle<String> name, VariableMode mode) {
|
||||
void Scope::DeclareParameter(const AstRawString* name, VariableMode mode) {
|
||||
ASSERT(!already_resolved());
|
||||
ASSERT(is_function_scope());
|
||||
Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
|
||||
@ -441,7 +455,7 @@ void Scope::DeclareParameter(Handle<String> name, VariableMode mode) {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::DeclareLocal(Handle<String> name,
|
||||
Variable* Scope::DeclareLocal(const AstRawString* name,
|
||||
VariableMode mode,
|
||||
InitializationFlag init_flag,
|
||||
Interface* interface) {
|
||||
@ -456,7 +470,7 @@ Variable* Scope::DeclareLocal(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::DeclareDynamicGlobal(Handle<String> name) {
|
||||
Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
|
||||
ASSERT(is_global_scope());
|
||||
return variables_.Declare(this,
|
||||
name,
|
||||
@ -479,7 +493,7 @@ void Scope::RemoveUnresolved(VariableProxy* var) {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::NewInternal(Handle<String> name) {
|
||||
Variable* Scope::NewInternal(const AstRawString* name) {
|
||||
ASSERT(!already_resolved());
|
||||
Variable* var = new(zone()) Variable(this,
|
||||
name,
|
||||
@ -492,7 +506,7 @@ Variable* Scope::NewInternal(Handle<String> name) {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::NewTemporary(Handle<String> name) {
|
||||
Variable* Scope::NewTemporary(const AstRawString* name) {
|
||||
ASSERT(!already_resolved());
|
||||
Variable* var = new(zone()) Variable(this,
|
||||
name,
|
||||
@ -530,7 +544,7 @@ Declaration* Scope::CheckConflictingVarDeclarations() {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Declaration* decl = decls_[i];
|
||||
if (decl->mode() != VAR) continue;
|
||||
Handle<String> name = decl->proxy()->name();
|
||||
const AstRawString* name = decl->proxy()->raw_name();
|
||||
|
||||
// Iterate through all scopes until and including the declaration scope.
|
||||
Scope* previous = NULL;
|
||||
@ -773,9 +787,8 @@ static void Indent(int n, const char* str) {
|
||||
}
|
||||
|
||||
|
||||
static void PrintName(Handle<String> name) {
|
||||
SmartArrayPointer<char> s = name->ToCString(DISALLOW_NULLS);
|
||||
PrintF("%s", s.get());
|
||||
static void PrintName(const AstRawString* name) {
|
||||
PrintF("%.*s", name->length(), name->raw_data());
|
||||
}
|
||||
|
||||
|
||||
@ -803,7 +816,7 @@ static void PrintVar(int indent, Variable* var) {
|
||||
if (var->is_used() || !var->IsUnallocated()) {
|
||||
Indent(indent, Variable::Mode2String(var->mode()));
|
||||
PrintF(" ");
|
||||
PrintName(var->name());
|
||||
PrintName(var->raw_name());
|
||||
PrintF("; // ");
|
||||
PrintLocation(var);
|
||||
if (var->has_forced_context_allocation()) {
|
||||
@ -829,7 +842,7 @@ void Scope::Print(int n) {
|
||||
|
||||
// Print header.
|
||||
Indent(n0, Header(scope_type_));
|
||||
if (scope_name_->length() > 0) {
|
||||
if (!scope_name_->IsEmpty()) {
|
||||
PrintF(" ");
|
||||
PrintName(scope_name_);
|
||||
}
|
||||
@ -839,7 +852,7 @@ void Scope::Print(int n) {
|
||||
PrintF(" (");
|
||||
for (int i = 0; i < params_.length(); i++) {
|
||||
if (i > 0) PrintF(", ");
|
||||
PrintName(params_[i]->name());
|
||||
PrintName(params_[i]->raw_name());
|
||||
}
|
||||
PrintF(")");
|
||||
}
|
||||
@ -849,7 +862,7 @@ void Scope::Print(int n) {
|
||||
// Function name, if any (named function literals, only).
|
||||
if (function_ != NULL) {
|
||||
Indent(n1, "// (local) function name: ");
|
||||
PrintName(function_->proxy()->name());
|
||||
PrintName(function_->proxy()->raw_name());
|
||||
PrintF("\n");
|
||||
}
|
||||
|
||||
@ -917,8 +930,8 @@ void Scope::Print(int n) {
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) {
|
||||
if (dynamics_ == NULL) dynamics_ = new(zone()) DynamicScopePart(zone());
|
||||
Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
|
||||
if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone());
|
||||
VariableMap* map = dynamics_->GetMap(mode);
|
||||
Variable* var = map->Lookup(name);
|
||||
if (var == NULL) {
|
||||
@ -938,7 +951,7 @@ Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) {
|
||||
}
|
||||
|
||||
|
||||
Variable* Scope::LookupRecursive(Handle<String> name,
|
||||
Variable* Scope::LookupRecursive(const AstRawString* name,
|
||||
BindingKind* binding_kind,
|
||||
AstNodeFactory<AstNullVisitor>* factory) {
|
||||
ASSERT(binding_kind != NULL);
|
||||
@ -1012,7 +1025,7 @@ bool Scope::ResolveVariable(CompilationInfo* info,
|
||||
|
||||
// Otherwise, try to resolve the variable.
|
||||
BindingKind binding_kind;
|
||||
Variable* var = LookupRecursive(proxy->name(), &binding_kind, factory);
|
||||
Variable* var = LookupRecursive(proxy->raw_name(), &binding_kind, factory);
|
||||
switch (binding_kind) {
|
||||
case BOUND:
|
||||
// We found a variable binding.
|
||||
@ -1024,29 +1037,29 @@ bool Scope::ResolveVariable(CompilationInfo* info,
|
||||
// scope which was not promoted to a context, this can happen if we use
|
||||
// debugger to evaluate arbitrary expressions at a break point).
|
||||
if (var->IsGlobalObjectProperty()) {
|
||||
var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
|
||||
var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
|
||||
} else if (var->is_dynamic()) {
|
||||
var = NonLocal(proxy->name(), DYNAMIC);
|
||||
var = NonLocal(proxy->raw_name(), DYNAMIC);
|
||||
} else {
|
||||
Variable* invalidated = var;
|
||||
var = NonLocal(proxy->name(), DYNAMIC_LOCAL);
|
||||
var = NonLocal(proxy->raw_name(), DYNAMIC_LOCAL);
|
||||
var->set_local_if_not_shadowed(invalidated);
|
||||
}
|
||||
break;
|
||||
|
||||
case UNBOUND:
|
||||
// No binding has been found. Declare a variable on the global object.
|
||||
var = info->global_scope()->DeclareDynamicGlobal(proxy->name());
|
||||
var = info->global_scope()->DeclareDynamicGlobal(proxy->raw_name());
|
||||
break;
|
||||
|
||||
case UNBOUND_EVAL_SHADOWED:
|
||||
// No binding has been found. But some scope makes a sloppy 'eval' call.
|
||||
var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
|
||||
var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
|
||||
break;
|
||||
|
||||
case DYNAMIC_LOOKUP:
|
||||
// The variable could not be resolved statically.
|
||||
var = NonLocal(proxy->name(), DYNAMIC);
|
||||
var = NonLocal(proxy->raw_name(), DYNAMIC);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1069,8 +1082,10 @@ bool Scope::ResolveVariable(CompilationInfo* info,
|
||||
if (FLAG_harmony_modules) {
|
||||
bool ok;
|
||||
#ifdef DEBUG
|
||||
if (FLAG_print_interface_details)
|
||||
PrintF("# Resolve %s:\n", var->name()->ToAsciiArray());
|
||||
if (FLAG_print_interface_details) {
|
||||
PrintF("# Resolve %.*s:\n", var->raw_name()->length(),
|
||||
var->raw_name()->raw_data());
|
||||
}
|
||||
#endif
|
||||
proxy->interface()->Unify(var->interface(), zone(), &ok);
|
||||
if (!ok) {
|
||||
@ -1150,7 +1165,7 @@ bool Scope::MustAllocate(Variable* var) {
|
||||
// Give var a read/write use if there is a chance it might be accessed
|
||||
// via an eval() call. This is only possible if the variable has a
|
||||
// visible name.
|
||||
if ((var->is_this() || var->name()->length() > 0) &&
|
||||
if ((var->is_this() || !var->raw_name()->IsEmpty()) &&
|
||||
(var->has_forced_context_allocation() ||
|
||||
scope_calls_eval_ ||
|
||||
inner_scope_calls_eval_ ||
|
||||
@ -1211,7 +1226,7 @@ void Scope::AllocateHeapSlot(Variable* var) {
|
||||
|
||||
void Scope::AllocateParameterLocals() {
|
||||
ASSERT(is_function_scope());
|
||||
Variable* arguments = LookupLocal(isolate_->factory()->arguments_string());
|
||||
Variable* arguments = LookupLocal(ast_value_factory_->arguments_string());
|
||||
ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
|
||||
|
||||
bool uses_sloppy_arguments = false;
|
||||
@ -1352,10 +1367,9 @@ void Scope::AllocateModulesRecursively(Scope* host_scope) {
|
||||
if (already_resolved()) return;
|
||||
if (is_module_scope()) {
|
||||
ASSERT(interface_->IsFrozen());
|
||||
Handle<String> name = isolate_->factory()->InternalizeOneByteString(
|
||||
STATIC_ASCII_VECTOR(".module"));
|
||||
ASSERT(module_var_ == NULL);
|
||||
module_var_ = host_scope->NewInternal(name);
|
||||
module_var_ =
|
||||
host_scope->NewInternal(ast_value_factory_->dot_module_string());
|
||||
++host_scope->num_modules_;
|
||||
}
|
||||
|
||||
|
44
src/scopes.h
44
src/scopes.h
@ -22,14 +22,14 @@ class VariableMap: public ZoneHashMap {
|
||||
virtual ~VariableMap();
|
||||
|
||||
Variable* Declare(Scope* scope,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
VariableMode mode,
|
||||
bool is_valid_lhs,
|
||||
Variable::Kind kind,
|
||||
InitializationFlag initialization_flag,
|
||||
Interface* interface = Interface::NewValue());
|
||||
|
||||
Variable* Lookup(Handle<String> name);
|
||||
Variable* Lookup(const AstRawString* name);
|
||||
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
@ -74,7 +74,8 @@ class Scope: public ZoneObject {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Construction
|
||||
|
||||
Scope(Scope* outer_scope, ScopeType scope_type, Zone* zone);
|
||||
Scope(Scope* outer_scope, ScopeType scope_type,
|
||||
AstValueFactory* value_factory, Zone* zone);
|
||||
|
||||
// Compute top scope and allocate variables. For lazy compilation the top
|
||||
// scope only contains the single lazily compiled function, so this
|
||||
@ -85,7 +86,9 @@ class Scope: public ZoneObject {
|
||||
Zone* zone);
|
||||
|
||||
// The scope name is only used for printing/debugging.
|
||||
void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }
|
||||
void SetScopeName(const AstRawString* scope_name) {
|
||||
scope_name_ = scope_name;
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
|
||||
@ -100,18 +103,18 @@ class Scope: public ZoneObject {
|
||||
// Declarations
|
||||
|
||||
// Lookup a variable in this scope. Returns the variable or NULL if not found.
|
||||
Variable* LookupLocal(Handle<String> name);
|
||||
Variable* LookupLocal(const AstRawString* name);
|
||||
|
||||
// This lookup corresponds to a lookup in the "intermediate" scope sitting
|
||||
// between this scope and the outer scope. (ECMA-262, 3rd., requires that
|
||||
// the name of named function literal is kept in an intermediate scope
|
||||
// in between this scope and the next outer scope.)
|
||||
Variable* LookupFunctionVar(Handle<String> name,
|
||||
Variable* LookupFunctionVar(const AstRawString* name,
|
||||
AstNodeFactory<AstNullVisitor>* factory);
|
||||
|
||||
// Lookup a variable in this scope or outer scopes.
|
||||
// Returns the variable or NULL if not found.
|
||||
Variable* Lookup(Handle<String> name);
|
||||
Variable* Lookup(const AstRawString* name);
|
||||
|
||||
// Declare the function variable for a function literal. This variable
|
||||
// is in an intermediate scope between this function scope and the the
|
||||
@ -124,11 +127,11 @@ class Scope: public ZoneObject {
|
||||
// Declare a parameter in this scope. When there are duplicated
|
||||
// parameters the rightmost one 'wins'. However, the implementation
|
||||
// expects all parameters to be declared and from left to right.
|
||||
void DeclareParameter(Handle<String> name, VariableMode mode);
|
||||
void DeclareParameter(const AstRawString* name, VariableMode mode);
|
||||
|
||||
// Declare a local variable in this scope. If the variable has been
|
||||
// declared before, the previously declared variable is returned.
|
||||
Variable* DeclareLocal(Handle<String> name,
|
||||
Variable* DeclareLocal(const AstRawString* name,
|
||||
VariableMode mode,
|
||||
InitializationFlag init_flag,
|
||||
Interface* interface = Interface::NewValue());
|
||||
@ -137,12 +140,12 @@ class Scope: public ZoneObject {
|
||||
// global scope. The variable was introduced (possibly from an inner
|
||||
// scope) by a reference to an unresolved variable with no intervening
|
||||
// with statements or eval calls.
|
||||
Variable* DeclareDynamicGlobal(Handle<String> name);
|
||||
Variable* DeclareDynamicGlobal(const AstRawString* name);
|
||||
|
||||
// Create a new unresolved variable.
|
||||
template<class Visitor>
|
||||
VariableProxy* NewUnresolved(AstNodeFactory<Visitor>* factory,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
Interface* interface = Interface::NewValue(),
|
||||
int position = RelocInfo::kNoPosition) {
|
||||
// Note that we must not share the unresolved variables with
|
||||
@ -167,13 +170,13 @@ class Scope: public ZoneObject {
|
||||
// for printing and cannot be used to find the variable. In particular,
|
||||
// the only way to get hold of the temporary is by keeping the Variable*
|
||||
// around.
|
||||
Variable* NewInternal(Handle<String> name);
|
||||
Variable* NewInternal(const AstRawString* name);
|
||||
|
||||
// Creates a new temporary variable in this scope. The name is only used
|
||||
// for printing and cannot be used to find the variable. In particular,
|
||||
// the only way to get hold of the temporary is by keeping the Variable*
|
||||
// around. The name should not clash with a legitimate variable names.
|
||||
Variable* NewTemporary(Handle<String> name);
|
||||
Variable* NewTemporary(const AstRawString* name);
|
||||
|
||||
// Adds the specific declaration node to the list of declarations in
|
||||
// this scope. The declarations are processed as part of entering
|
||||
@ -390,7 +393,7 @@ class Scope: public ZoneObject {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Strict mode support.
|
||||
bool IsDeclared(Handle<String> name) {
|
||||
bool IsDeclared(const AstRawString* name) {
|
||||
// During formal parameter list parsing the scope only contains
|
||||
// two variables inserted at initialization: "this" and "arguments".
|
||||
// "this" is an invalid parameter name and "arguments" is invalid parameter
|
||||
@ -421,7 +424,7 @@ class Scope: public ZoneObject {
|
||||
ScopeType scope_type_;
|
||||
|
||||
// Debugging support.
|
||||
Handle<String> scope_name_;
|
||||
const AstRawString* scope_name_;
|
||||
|
||||
// The variables declared in this scope:
|
||||
//
|
||||
@ -497,7 +500,7 @@ class Scope: public ZoneObject {
|
||||
|
||||
// Create a non-local variable with a given name.
|
||||
// These variables are looked up dynamically at runtime.
|
||||
Variable* NonLocal(Handle<String> name, VariableMode mode);
|
||||
Variable* NonLocal(const AstRawString* name, VariableMode mode);
|
||||
|
||||
// Variable resolution.
|
||||
// Possible results of a recursive variable lookup telling if and how a
|
||||
@ -548,7 +551,7 @@ class Scope: public ZoneObject {
|
||||
// Lookup a variable reference given by name recursively starting with this
|
||||
// scope. If the code is executed because of a call to 'eval', the context
|
||||
// parameter should be set to the calling context of 'eval'.
|
||||
Variable* LookupRecursive(Handle<String> name,
|
||||
Variable* LookupRecursive(const AstRawString* name,
|
||||
BindingKind* binding_kind,
|
||||
AstNodeFactory<AstNullVisitor>* factory);
|
||||
MUST_USE_RESULT
|
||||
@ -592,10 +595,12 @@ class Scope: public ZoneObject {
|
||||
private:
|
||||
// Construct a scope based on the scope info.
|
||||
Scope(Scope* inner_scope, ScopeType type, Handle<ScopeInfo> scope_info,
|
||||
Zone* zone);
|
||||
AstValueFactory* value_factory, Zone* zone);
|
||||
|
||||
// Construct a catch scope with a binding for the name.
|
||||
Scope(Scope* inner_scope, Handle<String> catch_variable_name, Zone* zone);
|
||||
Scope(Scope* inner_scope,
|
||||
const AstRawString* catch_variable_name,
|
||||
AstValueFactory* value_factory, Zone* zone);
|
||||
|
||||
void AddInnerScope(Scope* inner_scope) {
|
||||
if (inner_scope != NULL) {
|
||||
@ -608,6 +613,7 @@ class Scope: public ZoneObject {
|
||||
Scope* outer_scope,
|
||||
Handle<ScopeInfo> scope_info);
|
||||
|
||||
AstValueFactory* ast_value_factory_;
|
||||
Zone* zone_;
|
||||
};
|
||||
|
||||
|
20
src/utils.cc
20
src/utils.cc
@ -394,4 +394,24 @@ void init_memcopy_functions() {
|
||||
}
|
||||
|
||||
|
||||
bool DoubleToBoolean(double d) {
|
||||
// NaN, +0, and -0 should return the false object
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union IeeeDoubleLittleEndianArchType u;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
union IeeeDoubleBigEndianArchType u;
|
||||
#endif
|
||||
u.d = d;
|
||||
if (u.bits.exp == 2047) {
|
||||
// Detect NaN for IEEE double precision floating point.
|
||||
if ((u.bits.man_low | u.bits.man_high) != 0) return false;
|
||||
}
|
||||
if (u.bits.exp == 0) {
|
||||
// Detect +0, and -0 for IEEE double precision floating point.
|
||||
if ((u.bits.man_low | u.bits.man_high) == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
30
src/utils.h
30
src/utils.h
@ -1582,6 +1582,36 @@ class StringBuilder : public SimpleStringBuilder {
|
||||
};
|
||||
|
||||
|
||||
bool DoubleToBoolean(double d);
|
||||
|
||||
template <typename Stream>
|
||||
bool StringToArrayIndex(Stream* stream, uint32_t* index) {
|
||||
uint16_t ch = stream->GetNext();
|
||||
|
||||
// If the string begins with a '0' character, it must only consist
|
||||
// of it to be a legal array index.
|
||||
if (ch == '0') {
|
||||
*index = 0;
|
||||
return !stream->HasMore();
|
||||
}
|
||||
|
||||
// Convert string to uint32 array index; character by character.
|
||||
int d = ch - '0';
|
||||
if (d < 0 || d > 9) return false;
|
||||
uint32_t result = d;
|
||||
while (stream->HasMore()) {
|
||||
d = stream->GetNext() - '0';
|
||||
if (d < 0 || d > 9) return false;
|
||||
// Check that the new result is below the 32 bit limit.
|
||||
if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
|
||||
result = (result * 10) + d;
|
||||
}
|
||||
|
||||
*index = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_UTILS_H_
|
||||
|
@ -33,7 +33,7 @@ const char* Variable::Mode2String(VariableMode mode) {
|
||||
|
||||
|
||||
Variable::Variable(Scope* scope,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
VariableMode mode,
|
||||
bool is_valid_ref,
|
||||
Kind kind,
|
||||
@ -52,8 +52,6 @@ Variable::Variable(Scope* scope,
|
||||
is_used_(false),
|
||||
initialization_flag_(initialization_flag),
|
||||
interface_(interface) {
|
||||
// Names must be canonicalized for fast equality checks.
|
||||
ASSERT(name->IsInternalizedString());
|
||||
// Var declared variables never need initialization.
|
||||
ASSERT(!(mode == VAR && initialization_flag == kNeedsInitialization));
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef V8_VARIABLES_H_
|
||||
#define V8_VARIABLES_H_
|
||||
|
||||
#include "src/ast-value-factory.h"
|
||||
#include "src/interface.h"
|
||||
#include "src/zone.h"
|
||||
|
||||
@ -52,7 +53,7 @@ class Variable: public ZoneObject {
|
||||
};
|
||||
|
||||
Variable(Scope* scope,
|
||||
Handle<String> name,
|
||||
const AstRawString* name,
|
||||
VariableMode mode,
|
||||
bool is_valid_ref,
|
||||
Kind kind,
|
||||
@ -70,7 +71,8 @@ class Variable: public ZoneObject {
|
||||
// scope is only used to follow the context chain length.
|
||||
Scope* scope() const { return scope_; }
|
||||
|
||||
Handle<String> name() const { return name_; }
|
||||
Handle<String> name() const { return name_->string(); }
|
||||
const AstRawString* raw_name() const { return name_; }
|
||||
VariableMode mode() const { return mode_; }
|
||||
bool has_forced_context_allocation() const {
|
||||
return force_context_allocation_;
|
||||
@ -136,7 +138,7 @@ class Variable: public ZoneObject {
|
||||
|
||||
private:
|
||||
Scope* scope_;
|
||||
Handle<String> name_;
|
||||
const AstRawString* name_;
|
||||
VariableMode mode_;
|
||||
Kind kind_;
|
||||
Location location_;
|
||||
|
@ -41,7 +41,7 @@ TEST(List) {
|
||||
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Zone zone(isolate);
|
||||
AstNodeFactory<AstNullVisitor> factory(&zone);
|
||||
AstNodeFactory<AstNullVisitor> factory(&zone, NULL);
|
||||
AstNode* node = factory.NewEmptyStatement(RelocInfo::kNoPosition);
|
||||
list->Add(node);
|
||||
CHECK_EQ(1, list->length());
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/ast-value-factory.h"
|
||||
#include "src/compiler.h"
|
||||
#include "src/execution.h"
|
||||
#include "src/isolate.h"
|
||||
@ -796,8 +797,12 @@ void TestScanRegExp(const char* re_source, const char* expected) {
|
||||
CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
|
||||
CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
|
||||
scanner.Next(); // Current token is now the regexp literal.
|
||||
i::Zone zone(CcTest::i_isolate());
|
||||
i::AstValueFactory ast_value_factory(&zone,
|
||||
CcTest::i_isolate()->heap()->HashSeed());
|
||||
ast_value_factory.Internalize(CcTest::i_isolate());
|
||||
i::Handle<i::String> val =
|
||||
scanner.AllocateInternalizedString(CcTest::i_isolate());
|
||||
scanner.CurrentSymbol(&ast_value_factory)->string();
|
||||
i::DisallowHeapAllocation no_alloc;
|
||||
i::String::FlatContent content = val->GetFlatContent();
|
||||
CHECK(content.IsAscii());
|
||||
@ -2587,3 +2592,20 @@ TEST(FuncNameInferrerEscaped) {
|
||||
i::DeleteArray(two_byte_source);
|
||||
i::DeleteArray(two_byte_name);
|
||||
}
|
||||
|
||||
|
||||
TEST(RegressionLazyFunctionWithErrorWithArg) {
|
||||
// The bug occurred when a lazy function had an error which requires a
|
||||
// parameter (such as "unknown label" here). The error message was processed
|
||||
// before the AstValueFactory containing the error message string was
|
||||
// internalized.
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
LocalContext env;
|
||||
i::FLAG_lazy = true;
|
||||
i::FLAG_min_preparse_length = 0;
|
||||
CompileRun("function this_is_lazy() {\n"
|
||||
" break p;\n"
|
||||
"}\n"
|
||||
"this_is_lazy();\n");
|
||||
}
|
||||
|
@ -343,6 +343,8 @@
|
||||
'../../src/assembler.h',
|
||||
'../../src/assert-scope.h',
|
||||
'../../src/assert-scope.cc',
|
||||
'../../src/ast-value-factory.cc',
|
||||
'../../src/ast-value-factory.h',
|
||||
'../../src/ast.cc',
|
||||
'../../src/ast.h',
|
||||
'../../src/bignum-dtoa.cc',
|
||||
|
@ -44,6 +44,18 @@
|
||||
|
||||
using namespace v8::internal;
|
||||
|
||||
class StringResource8 : public v8::String::ExternalAsciiStringResource {
|
||||
public:
|
||||
StringResource8(const char* data, int length)
|
||||
: data_(data), length_(length) { }
|
||||
virtual size_t length() const { return length_; }
|
||||
virtual const char* data() const { return data_; }
|
||||
|
||||
private:
|
||||
const char* data_;
|
||||
int length_;
|
||||
};
|
||||
|
||||
std::pair<TimeDelta, TimeDelta> RunBaselineParser(
|
||||
const char* fname, Encoding encoding, int repeat, v8::Isolate* isolate,
|
||||
v8::Handle<v8::Context> context) {
|
||||
@ -63,7 +75,9 @@ std::pair<TimeDelta, TimeDelta> RunBaselineParser(
|
||||
break;
|
||||
}
|
||||
case LATIN1: {
|
||||
source_handle = v8::String::NewFromOneByte(isolate, source);
|
||||
StringResource8* string_resource =
|
||||
new StringResource8(reinterpret_cast<const char*>(source), length);
|
||||
source_handle = v8::String::NewExternal(isolate, string_resource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user