Skip to content

Commit

Permalink
Upgrade V8 to 2.3.5
Browse files Browse the repository at this point in the history
  • Loading branch information
ry committed Aug 4, 2010
1 parent 7db5c8a commit 81f5ed5
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 27 deletions.
9 changes: 9 additions & 0 deletions deps/v8/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
2010-08-04: Version 2.3.5

Added support for ES5 property names. Object initialisers and
dot-notation property access now allows keywords. Also allowed
non-identifiers after "get" or "set" in an object initialiser.

Randomize the addresses of allocated executable memory on Windows.


2010-08-02: Version 2.3.4

Fixed problems in implementation of ES5 function.prototype.bind.
Expand Down
58 changes: 45 additions & 13 deletions deps/v8/src/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ class Parser {
Literal* GetLiteralNumber(double value);

Handle<String> ParseIdentifier(bool* ok);
Handle<String> ParseIdentifierName(bool* ok);
Handle<String> ParseIdentifierOrGetOrSet(bool* is_get,
bool* is_set,
bool* ok);
Expand Down Expand Up @@ -3121,7 +3122,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
case Token::PERIOD: {
Consume(Token::PERIOD);
int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifier(CHECK_OK);
Handle<String> name = ParseIdentifierName(CHECK_OK);
result = factory()->NewProperty(result, NEW(Literal(name)), pos);
break;
}
Expand Down Expand Up @@ -3207,7 +3208,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
case Token::PERIOD: {
Consume(Token::PERIOD);
int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifier(CHECK_OK);
Handle<String> name = ParseIdentifierName(CHECK_OK);
result = factory()->NewProperty(result, NEW(Literal(name)), pos);
break;
}
Expand Down Expand Up @@ -3586,8 +3587,8 @@ void Parser::BuildObjectLiteralConstantProperties(
Expression* Parser::ParseObjectLiteral(bool* ok) {
// ObjectLiteral ::
// '{' (
// ((Identifier | String | Number) ':' AssignmentExpression)
// | (('get' | 'set') FunctionLiteral)
// ((IdentifierName | String | Number) ':' AssignmentExpression)
// | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
// )*[','] '}'

ZoneListWrapper<ObjectLiteral::Property> properties =
Expand All @@ -3597,7 +3598,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
Literal* key = NULL;
switch (peek()) {
Token::Value next = peek();
switch (next) {
case Token::IDENTIFIER: {
// Store identifier keys as literal symbols to avoid
// resolving them when compiling code for the object
Expand All @@ -3608,15 +3610,26 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
if (is_getter || is_setter) {
// Special handling of getter and setter syntax.
if (peek() == Token::IDENTIFIER) {
Handle<String> name = ParseIdentifier(CHECK_OK);
Handle<String> name;
next = peek();
if (next == Token::IDENTIFIER ||
next == Token::STRING ||
next == Token::NUMBER ||
Token::IsKeyword(next)) {
Consume(next);
Handle<String> name =
factory()->LookupSymbol(scanner_.literal_string(),
scanner_.literal_length());
FunctionLiteral* value =
ParseFunctionLiteral(name, RelocInfo::kNoPosition,
DECLARATION, CHECK_OK);
ParseFunctionLiteral(name,
RelocInfo::kNoPosition,
DECLARATION,
CHECK_OK);
ObjectLiteral::Property* property =
NEW(ObjectLiteral::Property(is_getter, value));
if (IsBoilerplateProperty(property))
if (IsBoilerplateProperty(property)) {
number_of_boilerplate_properties++;
}
properties.Add(property);
if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
continue; // restart the while
Expand All @@ -3625,14 +3638,20 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
key = NEW(Literal(id));
break;
}

#define CASE_KEYWORD(name, ignore1, ignore2) \
case Token::name:
TOKEN_LIST(IGNORE_TOKEN, CASE_KEYWORD, IGNORE_TOKEN)
#undef CASE_KEYWORD
// FALLTHROUGH - keyword tokens fall through to the same code as strings.
case Token::STRING: {
Consume(Token::STRING);
Consume(next);
Handle<String> string =
factory()->LookupSymbol(scanner_.literal_string(),
scanner_.literal_length());
uint32_t index;
if (!string.is_null() && string->AsArrayIndex(&index)) {
if (next == Token::STRING &&
!string.is_null() &&
string->AsArrayIndex(&index)) {
key = NewNumberLiteral(index);
} else {
key = NEW(Literal(string));
Expand Down Expand Up @@ -4008,6 +4027,19 @@ Handle<String> Parser::ParseIdentifier(bool* ok) {
scanner_.literal_length());
}


Handle<String> Parser::ParseIdentifierName(bool* ok) {
Token::Value next = Next();
if (next != Token::IDENTIFIER && !Token::IsKeyword(next)) {
ReportUnexpectedToken(next);
*ok = false;
return Handle<String>();
}
return factory()->LookupSymbol(scanner_.literal_string(),
scanner_.literal_length());
}


// This function reads an identifier and determines whether or not it
// is 'get' or 'set'. The reason for not using ParseIdentifier and
// checking on the output is that this involves heap allocation which
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/platform-linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ size_t OS::AllocateAlignment() {
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
// TODO(805): Port randomization of allocated executable memory to Linux.
const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Expand Down
28 changes: 27 additions & 1 deletion deps/v8/src/platform-win32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -838,12 +838,38 @@ size_t OS::AllocateAlignment() {
void* OS::Allocate(const size_t requested,
size_t* allocated,
bool is_executable) {
// The address range used to randomize RWX allocations in OS::Allocate
// Try not to map pages into the default range that windows loads DLLs
// Note: This does not guarantee RWX regions will be within the
// range kAllocationRandomAddressMin to kAllocationRandomAddressMax
#ifdef V8_HOST_ARCH_64_BIT
static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000;
static const intptr_t kAllocationRandomAddressMax = 0x000004FFFFFFFFFF;
#else
static const intptr_t kAllocationRandomAddressMin = 0x04000000;
static const intptr_t kAllocationRandomAddressMax = 0x4FFFFFFF;
#endif

// VirtualAlloc rounds allocated size to page size automatically.
size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
intptr_t address = NULL;

// Windows XP SP2 allows Data Excution Prevention (DEP).
int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
LPVOID mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);

// For exectutable pages try and randomize the allocation address
if (prot == PAGE_EXECUTE_READWRITE && msize >= Page::kPageSize) {
address = (V8::Random() << kPageSizeBits) | kAllocationRandomAddressMin;
address &= kAllocationRandomAddressMax;
}

LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address),
msize,
MEM_COMMIT | MEM_RESERVE,
prot);
if (mbase == NULL && address != NULL)
mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot);

if (mbase == NULL) {
LOG(StringEvent("OS::Allocate", "VirtualAlloc failed"));
return NULL;
Expand Down
11 changes: 5 additions & 6 deletions deps/v8/src/runtime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,13 @@ static Handle<Object> CreateObjectLiteralBoilerplate(
}
Handle<Object> result;
uint32_t element_index = 0;
if (key->IsSymbol()) {
// If key is a symbol it is not an array element.
Handle<String> name(String::cast(*key));
ASSERT(!name->AsArrayIndex(&element_index));
result = SetProperty(boilerplate, name, value, NONE);
} else if (key->ToArrayIndex(&element_index)) {
if (key->ToArrayIndex(&element_index)) {
// Array index (uint32).
result = SetElement(boilerplate, element_index, value);
} else if (key->IsSymbol()) {
// The key is not an array index.
Handle<String> name(String::cast(*key));
result = SetProperty(boilerplate, name, value, NONE);
} else {
// Non-uint32 number.
ASSERT(key->IsNumber());
Expand Down
8 changes: 8 additions & 0 deletions deps/v8/src/token.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,12 @@ int8_t Token::precedence_[NUM_TOKENS] = {
#undef T


#define KT(a, b, c) 'T',
#define KK(a, b, c) 'K',
const char Token::token_type[] = {
TOKEN_LIST(KT, KK, IGNORE_TOKEN)
};
#undef KT
#undef KK

} } // namespace v8::internal
5 changes: 5 additions & 0 deletions deps/v8/src/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ class Token {
}

// Predicates
static bool IsKeyword(Value tok) {
return token_type[tok] == 'K';
}

static bool IsAssignmentOp(Value tok) {
return INIT_VAR <= tok && tok <= ASSIGN_MOD;
}
Expand Down Expand Up @@ -263,6 +267,7 @@ class Token {
static const char* name_[NUM_TOKENS];
static const char* string_[NUM_TOKENS];
static int8_t precedence_[NUM_TOKENS];
static const char token_type[NUM_TOKENS];
};

} } // namespace v8::internal
Expand Down
4 changes: 2 additions & 2 deletions deps/v8/src/version.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 3
#define BUILD_NUMBER 4
#define PATCH_LEVEL 1
#define BUILD_NUMBER 5
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false

// Define SONAME to have the SCons build the put a specific SONAME into the
Expand Down
107 changes: 107 additions & 0 deletions deps/v8/test/mjsunit/object-literal.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,110 @@ a = makeRegexpInObject();
b = makeRegexpInObject();
assertTrue(a.a.b === b.a.b);
assertFalse(a.a.c === b.a.c);


// Test keywords valid as property names in initializers and dot-access.
var keywords = [
"break",
"case",
"catch",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"false",
"finally",
"for",
"function",
"if",
"in",
"instanceof",
"native",
"new",
"null",
"return",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
];

function testKeywordProperty(keyword) {
try {
// Sanity check that what we get is a keyword.
eval("var " + keyword + " = 42;");
assertUnreachable("Not a keyword: " + keyword);
} catch (e) { }

// Simple property, read and write.
var x = eval("({" + keyword + ": 42})");
assertEquals(42, x[keyword]);
assertEquals(42, eval("x." + keyword));
eval("x." + keyword + " = 37");
assertEquals(37, x[keyword]);
assertEquals(37, eval("x." + keyword));

// Getter/setter property, read and write.
var y = eval("({value : 42, get " + keyword + "(){return this.value}," +
" set " + keyword + "(v) { this.value = v; }})");
assertEquals(42, y[keyword]);
assertEquals(42, eval("y." + keyword));
eval("y." + keyword + " = 37");
assertEquals(37, y[keyword]);
assertEquals(37, eval("y." + keyword));

// Quoted keyword works is read back by unquoted as well.
var z = eval("({\"" + keyword + "\": 42})");
assertEquals(42, z[keyword]);
assertEquals(42, eval("z." + keyword));

// Function property, called.
var was_called;
function test_call() { this.was_called = true; was_called = true; }
var w = eval("({" + keyword + ": test_call, was_called: false})");
eval("w." + keyword + "();");
assertTrue(was_called);
assertTrue(w.was_called);

// Function property, constructed.
function construct() { this.constructed = true; }
var v = eval("({" + keyword + ": construct})");
var vo = eval("new v." + keyword + "()");
assertTrue(vo instanceof construct);
assertTrue(vo.constructed);
}

for (var i = 0; i < keywords.length; i++) {
testKeywordProperty(keywords[i]);
}

// Test getter and setter properties with string/number literal names.

var obj = {get 42() { return 42; },
get 3.14() { return "PI"; },
get "PI"() { return 3.14; },
readback: 0,
set 37(v) { this.readback = v; },
set 1.44(v) { this.readback = v; },
set "Poo"(v) { this.readback = v; }}

assertEquals(42, obj[42]);
assertEquals("PI", obj[3.14]);
assertEquals(3.14, obj["PI"]);
obj[37] = "t1";
assertEquals("t1", obj.readback);
obj[1.44] = "t2";
assertEquals("t2", obj.readback);
obj["Poo"] = "t3";
assertEquals("t3", obj.readback);


20 changes: 15 additions & 5 deletions deps/v8/test/sputnik/sputnik.status
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,6 @@ S15.5.4.11_D1.1_T1: PASS || FAIL_OK
S15.5.4.11_D1.1_T3: PASS || FAIL_OK
S12.6.4_D1: PASS || FAIL_OK

# We deliberately don't throw type errors when iterating through the
# undefined object
S9.9_A1: FAIL_OK
S9.9_A2: FAIL_OK

# We allow function declarations within statements
S12.5_A9_T1: FAIL_OK
S12.5_A9_T2: FAIL_OK
Expand All @@ -184,6 +179,21 @@ S15.3.4.2_A1_T1: FAIL_OK
S8.5_A2.2: PASS, FAIL if $system == linux, FAIL if $system == macos
S8.5_A2.1: PASS, FAIL if $system == linux, FAIL if $system == macos

##################### ES3 TESTS #########################
# These tests check for ES3 semantics, and differ from ES5.
# When we follow ES5 semantics, it's ok to fail the test.

# Allow keywords as names of properties in object initialisers and
# in dot-notation property access.
S11.1.5_A4.1: FAIL_OK
S11.1.5_A4.2: FAIL_OK

# Don't throw type errors when iterating through the undefined object.
S9.9_A1: FAIL_OK
S9.9_A2: FAIL_OK



##################### SKIPPED TESTS #####################

# These tests take a looong time to run in debug mode.
Expand Down

0 comments on commit 81f5ed5

Please sign in to comment.