Revision: 19215
Author: [email protected]
Date: Mon Feb 10 09:01:23 2014 UTC
Log: Version 3.24.35 (based on bleeding_edge revision r19214)
Fix inconsistencies wrt whitespaces (issue 3109).
Performance and stability improvements on all platforms.
http://code.google.com/p/v8/source/detail?r=19215
Added:
/trunk/src/zone-allocator.h
/trunk/src/zone-containers.h
Modified:
/trunk/ChangeLog
/trunk/include/v8.h
/trunk/src/heap-inl.h
/trunk/src/heap.cc
/trunk/src/heap.h
/trunk/src/hydrogen-gvn.cc
/trunk/src/hydrogen-gvn.h
/trunk/src/list.h
/trunk/src/parser.cc
/trunk/src/parser.h
/trunk/src/preparser.cc
/trunk/src/preparser.h
/trunk/src/utils.h
/trunk/src/version.cc
/trunk/src/x64/codegen-x64.cc
/trunk/src/x64/lithium-codegen-x64.cc
/trunk/src/x64/macro-assembler-x64.h
/trunk/test/cctest/test-api.cc
/trunk/test/cctest/test-parsing.cc
=======================================
--- /dev/null
+++ /trunk/src/zone-allocator.h Mon Feb 10 09:01:23 2014 UTC
@@ -0,0 +1,80 @@
+// 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_ZONE_ALLOCATOR_H_
+#define V8_ZONE_ALLOCATOR_H_
+
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+template<typename T>
+class zone_allocator {
+ public:
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ template<class O> struct rebind {
+ typedef zone_allocator<O> other;
+ };
+
+ explicit zone_allocator(Zone* zone) throw() : zone_(zone) {}
+ explicit zone_allocator(const zone_allocator& other) throw()
+ : zone_(other.zone_) {}
+ template<typename U> zone_allocator(const zone_allocator<U>&) throw() {}
+
+ pointer address(reference x) const {return &x;}
+ const_pointer address(const_reference x) const {return &x;}
+
+ pointer allocate(size_type count, const void* hint = 0) {
+ size_t size = count * sizeof(value_type);
+ size = RoundUp(size, kPointerSize);
+ return static_cast<pointer>(zone_->New(size));
+ }
+ void deallocate(pointer p, size_type) { /* noop for Zones */ }
+
+ size_type max_size() const throw() {
+ size_type max = static_cast<size_type>(-1) / sizeof(T);
+ return (max > 0 ? max : 1);
+ }
+ void construct(pointer p, const T& val) {
+ new(static_cast<void*>(p)) T(val);
+ }
+ void destroy(pointer p) { (static_cast<T*>(p))->~T(); }
+
+ private:
+ Zone* zone_;
+};
+
+} } // namespace v8::internal
+
+#endif // V8_ZONE_ALLOCATOR_H_
=======================================
--- /dev/null
+++ /trunk/src/zone-containers.h Mon Feb 10 09:01:23 2014 UTC
@@ -0,0 +1,46 @@
+// 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_ZONE_CONTAINERS_H_
+#define V8_ZONE_CONTAINERS_H_
+
+#include <vector>
+#include <set>
+
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+typedef zone_allocator<int> ZoneIntAllocator;
+typedef std::vector<int, ZoneIntAllocator> IntVector;
+typedef IntVector::iterator IntVectorIter;
+typedef IntVector::reverse_iterator IntVectorRIter;
+
+} } // namespace v8::internal
+
+#endif // V8_ZONE_CONTAINERS_H_
=======================================
--- /trunk/ChangeLog Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/ChangeLog Mon Feb 10 09:01:23 2014 UTC
@@ -1,3 +1,10 @@
+2014-02-10: Version 3.24.35
+
+ Fix inconsistencies wrt whitespaces (issue 3109).
+
+ Performance and stability improvements on all platforms.
+
+
2014-02-07: Version 3.24.34
Performance and stability improvements on all platforms.
=======================================
--- /trunk/include/v8.h Fri Jan 31 14:01:53 2014 UTC
+++ /trunk/include/v8.h Mon Feb 10 09:01:23 2014 UTC
@@ -5398,7 +5398,7 @@
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptyStringRootIndex = 146;
+ static const int kEmptyStringRootIndex = 147;
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
=======================================
--- /trunk/src/heap-inl.h Thu Feb 6 01:06:18 2014 UTC
+++ /trunk/src/heap-inl.h Mon Feb 10 09:01:23 2014 UTC
@@ -517,12 +517,8 @@
AllocationMemento* memento = AllocationMemento::cast(candidate);
if (!memento->IsValid()) return;
- if (memento->GetAllocationSite()->IncrementMementoFoundCount() &&
- heap->allocation_sites_scratchpad_length <
- kAllocationSiteScratchpadSize) {
- heap->allocation_sites_scratchpad[
- heap->allocation_sites_scratchpad_length++] =
- memento->GetAllocationSite();
+ if (memento->GetAllocationSite()->IncrementMementoFoundCount()) {
+ heap->AddAllocationSiteToScratchpad(memento->GetAllocationSite());
}
}
=======================================
--- /trunk/src/heap.cc Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/heap.cc Mon Feb 10 09:01:23 2014 UTC
@@ -150,7 +150,7 @@
#ifdef VERIFY_HEAP
no_weak_object_verification_scope_depth_(0),
#endif
- allocation_sites_scratchpad_length(0),
+ allocation_sites_scratchpad_length_(0),
promotion_queue_(this),
configured_(false),
external_string_table_(this),
@@ -516,16 +516,17 @@
// If the scratchpad overflowed, we have to iterate over the allocation
// sites list.
bool use_scratchpad =
- allocation_sites_scratchpad_length < kAllocationSiteScratchpadSize;
+ allocation_sites_scratchpad_length_ <
kAllocationSiteScratchpadSize;
int i = 0;
Object* list_element = allocation_sites_list();
bool trigger_deoptimization = false;
while (use_scratchpad ?
- i < allocation_sites_scratchpad_length :
+ i < allocation_sites_scratchpad_length_ :
list_element->IsAllocationSite()) {
AllocationSite* site = use_scratchpad ?
- allocation_sites_scratchpad[i] :
AllocationSite::cast(list_element);
+ AllocationSite::cast(allocation_sites_scratchpad()->get(i)) :
+ AllocationSite::cast(list_element);
allocation_mementos_found += site->memento_found_count();
if (site->memento_found_count() > 0) {
active_allocation_sites++;
@@ -546,7 +547,7 @@
if (trigger_deoptimization) isolate_->stack_guard()->DeoptMarkedCode();
- allocation_sites_scratchpad_length = 0;
+ FlushAllocationSitesScratchpad();
if (FLAG_trace_pretenuring_statistics &&
(allocation_mementos_found > 0 ||
@@ -3300,6 +3301,12 @@
// Handling of script id generation is in Factory::NewScript.
set_last_script_id(Smi::FromInt(v8::Script::kNoScriptId));
+ { MaybeObject* maybe_obj = AllocateAllocationSitesScratchpad();
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_allocation_sites_scratchpad(FixedArray::cast(obj));
+ InitializeAllocationSitesScratchpad();
+
// Initialize keyed lookup cache.
isolate_->keyed_lookup_cache()->Clear();
@@ -3587,6 +3594,39 @@
if (!maybe->To<Object>(&number)) return maybe;
return NumberToString(number, check_number_string_cache);
}
+
+
+MaybeObject* Heap::AllocateAllocationSitesScratchpad() {
+ MaybeObject* maybe_obj =
+ AllocateFixedArray(kAllocationSiteScratchpadSize, TENURED);
+ return maybe_obj;
+}
+
+
+void Heap::FlushAllocationSitesScratchpad() {
+ for (int i = 0; i < allocation_sites_scratchpad_length_; i++) {
+ allocation_sites_scratchpad()->set_undefined(i);
+ }
+ allocation_sites_scratchpad_length_ = 0;
+}
+
+
+void Heap::InitializeAllocationSitesScratchpad() {
+ ASSERT(allocation_sites_scratchpad()->length() ==
+ kAllocationSiteScratchpadSize);
+ for (int i = 0; i < kAllocationSiteScratchpadSize; i++) {
+ allocation_sites_scratchpad()->set_undefined(i);
+ }
+}
+
+
+void Heap::AddAllocationSiteToScratchpad(AllocationSite* site) {
+ if (allocation_sites_scratchpad_length_ < kAllocationSiteScratchpadSize)
{
+ allocation_sites_scratchpad()->set(
+ allocation_sites_scratchpad_length_, site);
+ allocation_sites_scratchpad_length_++;
+ }
+}
Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
=======================================
--- /trunk/src/heap.h Wed Feb 5 03:04:56 2014 UTC
+++ /trunk/src/heap.h Mon Feb 10 09:01:23 2014 UTC
@@ -202,7 +202,8 @@
V(SeededNumberDictionary,
empty_slow_element_dictionary, \
EmptySlowElementDictionary) \
V(Symbol, observed_symbol,
ObservedSymbol) \
- V(FixedArray, materialized_objects, MaterializedObjects)
+ V(FixedArray, materialized_objects,
MaterializedObjects) \
+ V(FixedArray, allocation_sites_scratchpad, AllocationSitesScratchpad)
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
@@ -2285,6 +2286,18 @@
// Flush the number to string cache.
void FlushNumberStringCache();
+ // Allocates a fixed-size allocation sites scratchpad.
+ MUST_USE_RESULT MaybeObject* AllocateAllocationSitesScratchpad();
+
+ // Sets used allocation sites entries to undefined.
+ void FlushAllocationSitesScratchpad();
+
+ // Initializes the allocation sites scratchpad with undefined values.
+ void InitializeAllocationSitesScratchpad();
+
+ // Adds an allocation site to the scratchpad if there is space left.
+ void AddAllocationSiteToScratchpad(AllocationSite* site);
+
void UpdateSurvivalRateTrend(int start_new_space_size);
enum SurvivalRateTrend { INCREASING, STABLE, DECREASING, FLUCTUATING };
@@ -2457,10 +2470,8 @@
int no_weak_object_verification_scope_depth_;
#endif
-
static const int kAllocationSiteScratchpadSize = 256;
- int allocation_sites_scratchpad_length;
- AllocationSite*
allocation_sites_scratchpad[kAllocationSiteScratchpadSize];
+ int allocation_sites_scratchpad_length_;
static const int kMaxMarkSweepsInIdleRound = 7;
static const int kIdleScavengeThreshold = 5;
=======================================
--- /trunk/src/hydrogen-gvn.cc Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/hydrogen-gvn.cc Mon Feb 10 09:01:23 2014 UTC
@@ -535,13 +535,9 @@
block->block_id(),
GetGVNFlagsString(side_effects).get());
- GVNFlagSet accumulated_first_time_depends;
- GVNFlagSet accumulated_first_time_changes;
HBasicBlock* last = block->loop_information()->GetLastBackEdge();
for (int j = block->block_id(); j <= last->block_id(); ++j) {
- ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects,
- &accumulated_first_time_depends,
- &accumulated_first_time_changes);
+ ProcessLoopBlock(graph()->blocks()->at(j), block, side_effects);
}
}
}
@@ -551,9 +547,7 @@
void HGlobalValueNumberingPhase::ProcessLoopBlock(
HBasicBlock* block,
HBasicBlock* loop_header,
- GVNFlagSet loop_kills,
- GVNFlagSet* first_time_depends,
- GVNFlagSet* first_time_changes) {
+ GVNFlagSet loop_kills) {
HBasicBlock* pre_header = loop_header->predecessors()->at(0);
GVNFlagSet depends_flags =
HValue::ConvertChangesToDependsFlags(loop_kills);
TRACE_GVN_2("Loop invariant motion for B%d %s\n",
@@ -562,7 +556,6 @@
HInstruction* instr = block->first();
while (instr != NULL) {
HInstruction* next = instr->next();
- bool hoisted = false;
if (instr->CheckFlag(HValue::kUseGVN)) {
TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n",
instr->id(),
@@ -589,26 +582,9 @@
instr->Unlink();
instr->InsertBefore(pre_header->end());
if (instr->HasSideEffects()) removed_side_effects_ = true;
- hoisted = true;
}
}
}
- if (!hoisted) {
- // If an instruction is not hoisted, we have to account for its side
- // effects when hoisting later HTransitionElementsKind instructions.
- GVNFlagSet previous_depends = *first_time_depends;
- GVNFlagSet previous_changes = *first_time_changes;
- first_time_depends->Add(instr->DependsOnFlags());
- first_time_changes->Add(instr->ChangesFlags());
- if (!(previous_depends == *first_time_depends)) {
- TRACE_GVN_1("Updated first-time accumulated %s\n",
- GetGVNFlagsString(*first_time_depends).get());
- }
- if (!(previous_changes == *first_time_changes)) {
- TRACE_GVN_1("Updated first-time accumulated %s\n",
- GetGVNFlagsString(*first_time_changes).get());
- }
- }
instr = next;
}
}
=======================================
--- /trunk/src/hydrogen-gvn.h Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/hydrogen-gvn.h Mon Feb 10 09:01:23 2014 UTC
@@ -52,9 +52,7 @@
void LoopInvariantCodeMotion();
void ProcessLoopBlock(HBasicBlock* block,
HBasicBlock* before_loop,
- GVNFlagSet loop_kills,
- GVNFlagSet* accumulated_first_time_depends,
- GVNFlagSet* accumulated_first_time_changes);
+ GVNFlagSet loop_kills);
bool AllowCodeMotion();
bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);
=======================================
--- /trunk/src/list.h Wed Jan 22 10:50:56 2014 UTC
+++ /trunk/src/list.h Mon Feb 10 09:01:23 2014 UTC
@@ -90,6 +90,10 @@
inline T& at(int i) const { return operator[](i); }
inline T& last() const { return at(length_ - 1); }
inline T& first() const { return at(0); }
+
+ typedef T* iterator;
+ inline iterator begin() const { return &data_[0]; }
+ inline iterator end() const { return &data_[length_]; }
INLINE(bool is_empty() const) { return length_ == 0; }
INLINE(int length() const) { return length_; }
=======================================
--- /trunk/src/parser.cc Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/parser.cc Mon Feb 10 09:01:23 2014 UTC
@@ -2486,23 +2486,21 @@
Expect(Token::RPAREN, CHECK_OK);
- if (peek() == Token::LBRACE) {
- Target target(&this->target_stack_, &catch_collector);
- VariableMode mode = is_extended_mode() ? LET : VAR;
- catch_variable =
- catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
+ Target target(&this->target_stack_, &catch_collector);
+ VariableMode mode = is_extended_mode() ? LET : VAR;
+ catch_variable =
+ catch_scope->DeclareLocal(name, mode, kCreatedInitialized);
- BlockState block_state(this, catch_scope);
- catch_block = ParseBlock(NULL, CHECK_OK);
- } else {
- Expect(Token::LBRACE, CHECK_OK);
- }
+ BlockState block_state(this, catch_scope);
+ catch_block = ParseBlock(NULL, CHECK_OK);
+
catch_scope->set_end_position(scanner().location().end_pos);
tok = peek();
}
Block* finally_block = NULL;
- if (tok == Token::FINALLY || catch_block == NULL) {
+ ASSERT(tok == Token::FINALLY || catch_block != NULL);
+ if (tok == Token::FINALLY) {
Consume(Token::FINALLY);
finally_block = ParseBlock(NULL, CHECK_OK);
}
@@ -3388,7 +3386,7 @@
// Parse the initial primary or function expression.
Expression* result = NULL;
if (peek() == Token::FUNCTION) {
- Expect(Token::FUNCTION, CHECK_OK);
+ Consume(Token::FUNCTION);
int function_token_position = position();
bool is_generator = allow_generators() && Check(Token::MUL);
Handle<String> name;
@@ -4068,8 +4066,12 @@
// '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
scope->set_start_position(scanner().location().beg_pos);
- Scanner::Location name_loc = Scanner::Location::invalid();
- Scanner::Location dupe_loc = Scanner::Location::invalid();
+
+ // We don't yet know if the function will be strict, so we cannot yet
+ // produce errors for parameter names or duplicates. However, we
remember
+ // the locations of these errors if they occur and produce the errors
later.
+ Scanner::Location eval_args_error_log = Scanner::Location::invalid();
+ Scanner::Location dupe_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid();
bool done = (peek() == Token::RPAREN);
@@ -4079,16 +4081,16 @@
ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
CHECK_OK);
// Store locations for possible future error reports.
- if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
- name_loc = scanner().location();
- }
- if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
- duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
- dupe_loc = scanner().location();
+ if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name))
{
+ eval_args_error_log = scanner().location();
}
if (!reserved_loc.IsValid() && is_strict_reserved) {
reserved_loc = scanner().location();
}
+ if (!dupe_error_loc.IsValid() && top_scope_->IsDeclared(param_name))
{
+ duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
+ dupe_error_loc = scanner().location();
+ }
top_scope_->DeclareParameter(param_name, VAR);
num_parameters++;
@@ -4256,7 +4258,8 @@
scope->set_end_position(scanner().location().end_pos);
}
- // Validate strict mode.
+ // Validate strict mode. We can do this only after parsing the
function,
+ // since the function can declare itself strict.
if (!top_scope_->is_classic_mode()) {
if (IsEvalOrArguments(function_name)) {
ReportMessageAt(function_name_location,
@@ -4265,20 +4268,20 @@
*ok = false;
return NULL;
}
- if (name_loc.IsValid()) {
- ReportMessageAt(name_loc, "strict_eval_arguments",
+ if (name_is_strict_reserved) {
+
ReportMessageAt(function_name_location, "unexpected_strict_reserved",
Vector<const char*>::empty());
*ok = false;
return NULL;
}
- if (dupe_loc.IsValid()) {
- ReportMessageAt(dupe_loc, "strict_param_dupe",
+ if (eval_args_error_log.IsValid()) {
+ ReportMessageAt(eval_args_error_log, "strict_eval_arguments",
Vector<const char*>::empty());
*ok = false;
return NULL;
}
- if (name_is_strict_reserved) {
-
ReportMessageAt(function_name_location, "unexpected_strict_reserved",
+ if (dupe_error_loc.IsValid()) {
+ ReportMessageAt(dupe_error_loc, "strict_param_dupe",
Vector<const char*>::empty());
*ok = false;
return NULL;
=======================================
--- /trunk/src/parser.h Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/parser.h Mon Feb 10 09:01:23 2014 UTC
@@ -649,9 +649,9 @@
ZoneList<Expression*>* ParseArguments(bool* ok);
FunctionLiteral* ParseFunctionLiteral(
- Handle<String> var_name,
+ Handle<String> name,
Scanner::Location function_name_location,
- bool name_is_reserved,
+ bool name_is_strict_reserved,
bool is_generator,
int function_token_position,
FunctionLiteral::FunctionType type,
=======================================
--- /trunk/src/preparser.cc Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/preparser.cc Mon Feb 10 09:01:23 2014 UTC
@@ -75,9 +75,6 @@
if (!scope_->is_classic_mode()) {
int end_pos = scanner()->location().end_pos;
CheckOctalLiteral(start_position, end_pos, &ok);
- if (ok) {
- CheckDelayedStrictModeViolation(start_position, end_pos, &ok);
- }
}
}
return kPreParseSuccess;
@@ -265,25 +262,14 @@
Expect(Token::FUNCTION, CHECK_OK);
bool is_generator = allow_generators() && Check(Token::MUL);
- Identifier identifier = ParseIdentifier(kDontAllowEvalOrArguments,
CHECK_OK);
- Scanner::Location location = scanner()->location();
-
- Expression function_value = ParseFunctionLiteral(is_generator, CHECK_OK);
-
- // If we're in strict mode, ParseIdentifier will catch using eval,
arguments
- // or a strict reserved word as function name. However, if only the
function
- // is strict, we need to do an extra check.
- if (function_value.IsStrictFunction() &&
- !identifier.IsValidStrictVariable()) {
- // Strict mode violation, using either reserved word or eval/arguments
- // as name of strict function.
- const char* type = "strict_eval_arguments";
- if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
- type = "unexpected_strict_reserved";
- }
- ReportMessageAt(location, type, NULL);
- *ok = false;
- }
+ bool is_strict_reserved = false;
+ Identifier name = ParseIdentifierOrStrictReservedWord(
+ &is_strict_reserved, CHECK_OK);
+ ParseFunctionLiteral(name,
+ scanner()->location(),
+ is_strict_reserved,
+ is_generator,
+ CHECK_OK);
return Statement::FunctionDeclaration();
}
@@ -713,15 +699,17 @@
// Finally ::
// 'finally' Block
- // In preparsing, allow any number of catch/finally blocks, including
zero
- // of both.
-
Expect(Token::TRY, CHECK_OK);
ParseBlock(CHECK_OK);
- bool catch_or_finally_seen = false;
- if (peek() == Token::CATCH) {
+ Token::Value tok = peek();
+ if (tok != Token::CATCH && tok != Token::FINALLY) {
+ ReportMessageAt(scanner()->location(), "no_catch_or_finally", NULL);
+ *ok = false;
+ return Statement::Default();
+ }
+ if (tok == Token::CATCH) {
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
@@ -729,15 +717,11 @@
{ Scope::InsideWith iw(scope_);
ParseBlock(CHECK_OK);
}
- catch_or_finally_seen = true;
+ tok = peek();
}
- if (peek() == Token::FINALLY) {
+ if (tok == Token::FINALLY) {
Consume(Token::FINALLY);
ParseBlock(CHECK_OK);
- catch_or_finally_seen = true;
- }
- if (!catch_or_finally_seen) {
- *ok = false;
}
return Statement::Default();
}
@@ -1021,20 +1005,19 @@
Consume(Token::FUNCTION);
bool is_generator = allow_generators() && Check(Token::MUL);
- Identifier identifier = Identifier::Default();
+ Identifier name = Identifier::Default();
+ bool is_strict_reserved_name = false;
+ Scanner::Location function_name_location =
Scanner::Location::invalid();
if (peek_any_identifier()) {
- identifier = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
+ CHECK_OK);
+ function_name_location = scanner()->location();
}
- result = ParseFunctionLiteral(is_generator, CHECK_OK);
- // If we're in strict mode, ParseIdentifier will catch using eval,
arguments
- // or a strict reserved word as function name. However, if only the
function
- // is strict, we need to do an extra check.
- if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) {
- StrictModeIdentifierViolation(scanner()->location(),
- identifier,
- ok);
- return Expression::Default();
- }
+ result = ParseFunctionLiteral(name,
+ function_name_location,
+ is_strict_reserved_name,
+ is_generator,
+ CHECK_OK);
} else {
result = ParsePrimaryExpression(CHECK_OK);
}
@@ -1216,7 +1199,11 @@
}
PropertyKind type = is_getter ? kGetterProperty :
kSetterProperty;
checker.CheckProperty(name, type, CHECK_OK);
- ParseFunctionLiteral(false, CHECK_OK);
+ ParseFunctionLiteral(Identifier::Default(),
+ scanner()->location(),
+ false, // reserved words are allowed here
+ false, // not a generator
+ CHECK_OK);
if (peek() != Token::RBRACE) {
Expect(Token::COMMA, CHECK_OK);
}
@@ -1302,9 +1289,12 @@
return argc;
}
-
-PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator,
- bool* ok) {
+PreParser::Expression PreParser::ParseFunctionLiteral(
+ Identifier function_name,
+ Scanner::Location function_name_location,
+ bool name_is_strict_reserved,
+ bool is_generator,
+ bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -1319,8 +1309,23 @@
int start_position = position();
bool done = (peek() == Token::RPAREN);
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
+ // We don't yet know if the function will be strict, so we cannot yet
produce
+ // errors for parameter names or duplicates. However, we remember the
+ // locations of these errors if they occur and produce the errors later.
+ Scanner::Location eval_args_error_loc = Scanner::Location::invalid();
+ Scanner::Location dupe_error_loc = Scanner::Location::invalid();
+ Scanner::Location reserved_error_loc = Scanner::Location::invalid();
while (!done) {
- ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+ bool is_strict_reserved = false;
+ Identifier param_name =
+ ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
+ if (!eval_args_error_loc.IsValid() && param_name.IsEvalOrArguments()) {
+ eval_args_error_loc = scanner()->location();
+ }
+ if (!reserved_error_loc.IsValid() && is_strict_reserved) {
+ reserved_error_loc = scanner()->location();
+ }
+
int prev_value;
if (scanner()->is_literal_ascii()) {
prev_value =
@@ -1330,11 +1335,10 @@
duplicate_finder.AddUtf16Symbol(scanner()->literal_utf16_string(), 1);
}
- if (prev_value != 0) {
- SetStrictModeViolation(scanner()->location(),
- "strict_param_dupe",
- CHECK_OK);
+ if (!dupe_error_loc.IsValid() && prev_value != 0) {
+ dupe_error_loc = scanner()->location();
}
+
done = (peek() == Token::RPAREN);
if (!done) {
Expect(Token::COMMA, CHECK_OK);
@@ -1358,10 +1362,41 @@
}
Expect(Token::RBRACE, CHECK_OK);
+ // Validate strict mode. We can do this only after parsing the function,
+ // since the function can declare itself strict.
if (!scope_->is_classic_mode()) {
+ if (function_name.IsEvalOrArguments()) {
+ ReportMessageAt(function_name_location, "strict_eval_arguments",
NULL);
+ *ok = false;
+ return Expression::Default();
+ }
+ if (name_is_strict_reserved) {
+ ReportMessageAt(
+ function_name_location, "unexpected_strict_reserved", NULL);
+ *ok = false;
+ return Expression::Default();
+ }
+ if (eval_args_error_loc.IsValid()) {
+ ReportMessageAt(eval_args_error_loc, "strict_eval_arguments",
+ Vector<const char*>::empty());
+ *ok = false;
+ return Expression::Default();
+ }
+ if (dupe_error_loc.IsValid()) {
+ ReportMessageAt(dupe_error_loc, "strict_param_dupe",
+ Vector<const char*>::empty());
+ *ok = false;
+ return Expression::Default();
+ }
+ if (reserved_error_loc.IsValid()) {
+ ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved",
+ Vector<const char*>::empty());
+ *ok = false;
+ return Expression::Default();
+ }
+
int end_position = scanner()->location().end_pos;
CheckOctalLiteral(start_position, end_position, CHECK_OK);
- CheckDelayedStrictModeViolation(start_position, end_position,
CHECK_OK);
return Expression::StrictFunction();
}
@@ -1467,7 +1502,8 @@
PreParser::Identifier name = GetIdentifierSymbol();
if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
!scope_->is_classic_mode() && name.IsEvalOrArguments()) {
- StrictModeIdentifierViolation(scanner()->location(), name, ok);
+ ReportMessageAt(scanner()->location(), "strict_eval_arguments",
NULL);
+ *ok = false;
}
return name;
} else if (scope_->is_classic_mode() &&
@@ -1482,55 +1518,22 @@
}
-void PreParser::SetStrictModeViolation(Scanner::Location location,
- const char* type,
- bool* ok) {
- if (!scope_->is_classic_mode()) {
- ReportMessageAt(location, type, NULL);
- *ok = false;
- return;
- }
- // Delay report in case this later turns out to be strict code
- // (i.e., for function names and parameters prior to a "use strict"
- // directive).
- // It's safe to overwrite an existing violation.
- // It's either from a function that turned out to be non-strict,
- // or it's in the current function (and we just need to report
- // one error), or it's in a unclosed nesting function that wasn't
- // strict (otherwise we would already be in strict mode).
- strict_mode_violation_location_ = location;
- strict_mode_violation_type_ = type;
-}
-
-
-void PreParser::CheckDelayedStrictModeViolation(int beg_pos,
- int end_pos,
- bool* ok) {
- Scanner::Location location = strict_mode_violation_location_;
- if (location.IsValid() &&
- location.beg_pos > beg_pos && location.end_pos < end_pos) {
- ReportMessageAt(location, strict_mode_violation_type_, NULL);
- *ok = false;
- }
-}
-
-
-void PreParser::StrictModeIdentifierViolation(Scanner::Location location,
- Identifier identifier,
- bool* ok) {
- const char* type = "strict_eval_arguments";
- if (identifier.IsFutureReserved()) {
- type = "unexpected_reserved";
- } else if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
- type = "unexpected_strict_reserved";
- }
- if (!scope_->is_classic_mode()) {
- ReportMessageAt(location, type, NULL);
+// Parses and identifier or a strict mode future reserved word, and
indicate
+// whether it is strict mode future reserved.
+PreParser::Identifier PreParser::ParseIdentifierOrStrictReservedWord(
+ bool* is_strict_reserved, bool* ok) {
+ Token::Value next = Next();
+ if (next == Token::IDENTIFIER) {
+ *is_strict_reserved = false;
+ } else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+ (next == Token::YIELD && !scope_->is_generator())) {
+ *is_strict_reserved = true;
+ } else {
+ ReportUnexpectedToken(next);
*ok = false;
- return;
+ return Identifier::Default();
}
- strict_mode_violation_location_ = location;
- strict_mode_violation_type_ = type;
+ return GetIdentifierSymbol();
}
=======================================
--- /trunk/src/preparser.h Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/preparser.h Mon Feb 10 09:01:23 2014 UTC
@@ -243,8 +243,6 @@
: ParserBase(scanner, stack_limit),
log_(log),
scope_(NULL),
- strict_mode_violation_location_(Scanner::Location::invalid()),
- strict_mode_violation_type_(NULL),
parenthesized_function_(false) { }
~PreParser() {}
@@ -616,10 +614,17 @@
Expression ParseV8Intrinsic(bool* ok);
Arguments ParseArguments(bool* ok);
- Expression ParseFunctionLiteral(bool is_generator, bool* ok);
+ Expression ParseFunctionLiteral(
+ Identifier name,
+ Scanner::Location function_name_location,
+ bool name_is_strict_reserved,
+ bool is_generator,
+ bool* ok);
void ParseLazyFunctionLiteralBody(bool* ok);
Identifier ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok);
+ Identifier ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
+ bool* ok);
Identifier ParseIdentifierName(bool* ok);
Identifier ParseIdentifierNameOrGetOrSet(bool* is_get,
bool* is_set,
@@ -648,20 +653,8 @@
bool CheckInOrOf(bool accept_OF);
- void SetStrictModeViolation(Scanner::Location,
- const char* type,
- bool* ok);
-
- void CheckDelayedStrictModeViolation(int beg_pos, int end_pos, bool* ok);
-
- void StrictModeIdentifierViolation(Scanner::Location,
- Identifier identifier,
- bool* ok);
-
ParserRecorder* log_;
Scope* scope_;
- Scanner::Location strict_mode_violation_location_;
- const char* strict_mode_violation_type_;
bool parenthesized_function_;
};
=======================================
--- /trunk/src/utils.h Wed Jan 15 10:29:52 2014 UTC
+++ /trunk/src/utils.h Mon Feb 10 09:01:23 2014 UTC
@@ -1140,6 +1140,21 @@
int id_;
};
+
+template <class C>
+class ContainerPointerWrapper {
+ public:
+ typedef typename C::iterator iterator;
+ typedef typename C::reverse_iterator reverse_iterator;
+ explicit ContainerPointerWrapper(C* container) : container_(container) {}
+ iterator begin() { return container_->begin(); }
+ iterator end() { return container_->end(); }
+ reverse_iterator rbegin() { return container_->rbegin(); }
+ reverse_iterator rend() { return container_->rend(); }
+ private:
+ C* container_;
+};
+
} } // namespace v8::internal
#endif // V8_UTILS_H_
=======================================
--- /trunk/src/version.cc Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/src/version.cc Mon Feb 10 09:01:23 2014 UTC
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 24
-#define BUILD_NUMBER 34
+#define BUILD_NUMBER 35
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
=======================================
--- /trunk/src/x64/codegen-x64.cc Mon Jan 27 01:05:32 2014 UTC
+++ /trunk/src/x64/codegen-x64.cc Mon Feb 10 09:01:23 2014 UTC
@@ -422,7 +422,7 @@
// Non-hole double, copy value into a heap number.
__ AllocateHeapNumber(rax, r15, &gc_required);
// rax: new heap number
- __ MoveDouble(FieldOperand(rax, HeapNumber::kValueOffset), r14);
+ __ movq(FieldOperand(rax, HeapNumber::kValueOffset), r14);
__ movp(FieldOperand(r11,
r9,
times_pointer_size,
=======================================
--- /trunk/src/x64/lithium-codegen-x64.cc Sat Feb 1 08:54:43 2014 UTC
+++ /trunk/src/x64/lithium-codegen-x64.cc Mon Feb 10 09:01:23 2014 UTC
@@ -3417,10 +3417,10 @@
__ LoadFromSafepointRegisterSlot(input_reg, input_reg);
__ bind(&allocated);
- __ MoveDouble(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset));
+ __ movq(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset));
__ shl(tmp2, Immediate(1));
__ shr(tmp2, Immediate(1));
- __ MoveDouble(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2);
+ __ movq(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2);
__ StoreToSafepointRegisterSlot(input_reg, tmp);
__ bind(&done);
=======================================
--- /trunk/src/x64/macro-assembler-x64.h Tue Jan 28 07:51:38 2014 UTC
+++ /trunk/src/x64/macro-assembler-x64.h Mon Feb 10 09:01:23 2014 UTC
@@ -841,9 +841,6 @@
void Pop(Register dst) { pop(dst); }
void PushReturnAddressFrom(Register src) { push(src); }
void PopReturnAddressTo(Register dst) { pop(dst); }
- void MoveDouble(Register dst, const Operand& src) { movq(dst, src); }
- void MoveDouble(const Operand& dst, Register src) { movq(dst, src); }
-
void Move(Register dst, ExternalReference ext) {
movp(dst, reinterpret_cast<Address>(ext.address()),
RelocInfo::EXTERNAL_REFERENCE);
=======================================
--- /trunk/test/cctest/test-api.cc Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/test/cctest/test-api.cc Mon Feb 10 09:01:23 2014 UTC
@@ -7044,28 +7044,6 @@
CHECK(context.IsEmpty());
CHECK_NE(last_location, NULL);
}
-
-
-static const char* js_code_causing_huge_string_flattening =
- "var str = 'X';"
- "for (var i = 0; i < 30; i++) {"
- " str = str + str;"
- "}"
- "str.match(/X/);";
-
-
-TEST(RegexpOutOfMemory) {
- // Execute a script that causes out of memory when flattening a string.
- v8::HandleScope scope(CcTest::isolate());
- v8::V8::SetFatalErrorHandler(OOMCallback);
- LocalContext context;
- Local<Script> script = Script::Compile(String::NewFromUtf8(
- CcTest::isolate(), js_code_causing_huge_string_flattening));
- last_location = NULL;
- script->Run();
-
- CHECK(false); // Should not return.
-}
static void MissingScriptInfoMessageListener(v8::Handle<v8::Message>
message,
@@ -7084,93 +7062,6 @@
Script::Compile(v8_str("throw Error()"))->Run();
v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
}
-
-
-int global_index = 0;
-
-template<typename T>
-class Snorkel {
- public:
- explicit Snorkel(v8::Persistent<T>* handle) : handle_(handle) {
- index_ = global_index++;
- }
- v8::Persistent<T>* handle_;
- int index_;
-};
-
-class Whammy {
- public:
- explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
- ~Whammy() { script_.Reset(); }
- v8::Handle<Script> getScript() {
- if (script_.IsEmpty()) script_.Reset(isolate_,
v8_compile("({}).blammo"));
- return Local<Script>::New(isolate_, script_);
- }
-
- public:
- static const int kObjectCount = 256;
- int cursor_;
- v8::Isolate* isolate_;
- v8::Persistent<v8::Object> objects_[kObjectCount];
- v8::Persistent<Script> script_;
-};
-
-static void HandleWeakReference(
- const v8::WeakCallbackData<v8::Value, Snorkel<v8::Value> >& data) {
- data.GetParameter()->handle_->ClearWeak();
- delete data.GetParameter();
-}
-
-void WhammyPropertyGetter(Local<String> name,
- const v8::PropertyCallbackInfo<v8::Value>& info)
{
- Whammy* whammy =
-
static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
-
- v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
-
- v8::Handle<v8::Object> obj = v8::Object::New(info.GetIsolate());
- if (!prev.IsEmpty()) {
- v8::Local<v8::Object>::New(info.GetIsolate(), prev)
- ->Set(v8_str("next"), obj);
- prev.SetWeak<Value, Snorkel<Value> >(new
Snorkel<Value>(&prev.As<Value>()),
- &HandleWeakReference);
- }
- whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
- whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
- info.GetReturnValue().Set(whammy->getScript()->Run());
-}
-
-
-TEST(WeakReference) {
- i::FLAG_expose_gc = true;
- v8::Isolate* isolate = CcTest::isolate();
- v8::HandleScope handle_scope(isolate);
- v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(isolate);
- Whammy* whammy = new Whammy(CcTest::isolate());
- templ->SetNamedPropertyHandler(WhammyPropertyGetter,
- 0, 0, 0, 0,
- v8::External::New(CcTest::isolate(),
whammy));
- const char* extension_list[] = { "v8/gc" };
- v8::ExtensionConfiguration extensions(1, extension_list);
- v8::Handle<Context> context =
- Context::New(CcTest::isolate(), &extensions);
- Context::Scope context_scope(context);
-
- v8::Handle<v8::Object> interceptor = templ->NewInstance();
- context->Global()->Set(v8_str("whammy"), interceptor);
- const char* code =
- "var last;"
- "for (var i = 0; i < 10000; i++) {"
- " var obj = whammy.length;"
- " if (last) last.next = obj;"
- " last = obj;"
- "}"
- "gc();"
- "4";
- v8::Handle<Value> result = CompileRun(code);
- CHECK_EQ(4.0, result->NumberValue());
- delete whammy;
-}
struct FlagAndPersistent {
@@ -14934,6 +14825,7 @@
delete sd;
delete deserialized_sd;
+ i::DeleteArray(serialized_data);
}
@@ -14982,6 +14874,7 @@
*exception_value);
try_catch.Reset();
+ delete sd;
// Overwrite function bar's start position with 200. The function entry
// will not be found when searching for it by position and we should fall
@@ -15298,6 +15191,7 @@
timeout_thread.Join();
regexp_interruption_data.string.Reset();
+ i::DeleteArray(uc16_content);
}
#endif // V8_INTERPRETED_REGEXP
@@ -19156,18 +19050,20 @@
UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
v8::Isolate* isolate = v8::Isolate::New();
- CHECK(isolate);
- isolate->Enter();
- v8::HandleScope scope(isolate);
- LocalContext context(isolate);
- // Run something in this isolate.
- ExpectTrue("true");
- v8::V8::SetFatalErrorHandler(StoringErrorCallback);
- last_location = last_message = NULL;
- // Still entered, should fail.
+ {
+ v8::Isolate::Scope i_scope(isolate);
+ v8::HandleScope scope(isolate);
+ LocalContext context(isolate);
+ // Run something in this isolate.
+ ExpectTrue("true");
+ v8::V8::SetFatalErrorHandler(StoringErrorCallback);
+ last_location = last_message = NULL;
+ // Still entered, should fail.
+ isolate->Dispose();
+ CHECK_NE(last_location, NULL);
+ CHECK_NE(last_message, NULL);
+ }
isolate->Dispose();
- CHECK_NE(last_location, NULL);
- CHECK_NE(last_message, NULL);
}
@@ -19382,6 +19278,7 @@
CHECK(v->IsNumber());
CHECK_EQ(22, static_cast<int>(v->NumberValue()));
}
+ isolate->Dispose();
}
class InitDefaultIsolateThread : public v8::internal::Thread {
=======================================
--- /trunk/test/cctest/test-parsing.cc Fri Feb 7 09:11:16 2014 UTC
+++ /trunk/test/cctest/test-parsing.cc Mon Feb 10 09:01:23 2014 UTC
@@ -1874,3 +1874,142 @@
RunParserSyncTest(context_data, statement_data, kSuccess);
}
+
+
+TEST(DontRegressPreParserDataSizes) {
+ // These tests make sure that PreParser doesn't start producing less
data.
+
+ v8::V8::Initialize();
+
+ int marker;
+ CcTest::i_isolate()->stack_guard()->SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ struct TestCase {
+ const char* program;
+ int symbols;
+ int functions;
+ } test_cases[] = {
+ // Labels, variables and functions are recorded as symbols.
+ {"{label: 42}", 1, 0}, {"{label: 42; label2: 43}", 2, 0},
+ {"var x = 42;", 1, 0}, {"var x = 42, y = 43;", 2, 0},
+ {"function foo() {}", 1, 1}, {"function foo() {} function bar() {}",
2, 2},
+ // Labels, variables and functions insize lazy functions are not
recorded.
+ {"function lazy() { var a, b, c; }", 1, 1},
+ {"function lazy() { a: 1; b: 2; c: 3; }", 1, 1},
+ {"function lazy() { function a() {} function b() {} function c() {}
}", 1,
+ 1},
+ {NULL, 0, 0}
+ };
+ // Each function adds 5 elements to the preparse function data.
+ const int kDataPerFunction = 5;
+
+ uintptr_t stack_limit =
CcTest::i_isolate()->stack_guard()->real_climit();
+ for (int i = 0; test_cases[i].program; i++) {
+ const char* program = test_cases[i].program;
+ i::Utf8ToUtf16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
+ i::CompleteParserRecorder log;
+ i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+ scanner.Initialize(&stream);
+
+ i::PreParser preparser(&scanner, &log, stack_limit);
+ preparser.set_allow_lazy(true);
+ preparser.set_allow_natives_syntax(true);
+ i::PreParser::PreParseResult result = preparser.PreParseProgram();
+ CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+ if (log.symbol_ids() != test_cases[i].symbols) {
+ i::OS::Print(
+ "Expected preparse data for program:\n"
+ "\t%s\n"
+ "to contain %d symbols, however, received %d symbols.\n",
+ program, test_cases[i].symbols, log.symbol_ids());
+ CHECK(false);
+ }
+ if (log.function_position() != test_cases[i].functions *
kDataPerFunction) {
+ i::OS::Print(
+ "Expected preparse data for program:\n"
+ "\t%s\n"
+ "to contain %d functions, however, received %d functions.\n",
+ program, test_cases[i].functions,
+ log.function_position() / kDataPerFunction);
+ CHECK(false);
+ }
+ i::ScriptDataImpl data(log.ExtractData());
+ CHECK(!data.has_error());
+ }
+}
+
+
+TEST(FunctionDeclaresItselfStrict) {
+ // Tests that we produce the right kinds of errors when a function
declares
+ // itself strict (we cannot produce there errors as soon as we see the
+ // offending identifiers, because we don't know at that point whether the
+ // function is strict or not).
+ const char* context_data[][2] = {
+ {"function eval() {", "}"},
+ {"function arguments() {", "}"},
+ {"function yield() {", "}"},
+ {"function interface() {", "}"},
+ {"function foo(eval) {", "}"},
+ {"function foo(arguments) {", "}"},
+ {"function foo(yield) {", "}"},
+ {"function foo(interface) {", "}"},
+ {"function foo(bar, eval) {", "}"},
+ {"function foo(bar, arguments) {", "}"},
+ {"function foo(bar, yield) {", "}"},
+ {"function foo(bar, interface) {", "}"},
+ {"function foo(bar, bar) {", "}"},
+ { NULL, NULL }
+ };
+
+ const char* strict_statement_data[] = {
+ "\"use strict\";",
+ NULL
+ };
+
+ const char* non_strict_statement_data[] = {
+ ";",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, strict_statement_data, kError);
+ RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
+}
+
+
+TEST(ErrorsTryWithoutCatchOrFinally) {
+ const char* context_data[][2] = {
+ {"", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "try { }",
+ "try { } foo();",
+ "try { } catch (e) foo();",
+ "try { } catch { }",
+ "try { } finally foo();",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsTryCatchFinally) {
+ const char* context_data[][2] = {
+ {"", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "try { } catch (e) { }",
+ "try { } catch (e) { } finally { }",
+ "try { } finally { }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.