mirror of
https://github.com/nodejs/node-v0.x-archive.git
synced 2026-04-28 03:01:10 -04:00
Upgrade V8 to 3.6.2
This commit is contained in:
5
deps/v8/.gitignore
vendored
5
deps/v8/.gitignore
vendored
@@ -1,17 +1,18 @@
|
||||
*.a
|
||||
*.exe
|
||||
*.idb
|
||||
*.lib
|
||||
*.log
|
||||
*.map
|
||||
*.mk
|
||||
*.ncb
|
||||
*.pdb
|
||||
*.pyc
|
||||
*.scons*
|
||||
*.so
|
||||
*.suo
|
||||
*.user
|
||||
*.xcodeproj
|
||||
*.idb
|
||||
*.pdb
|
||||
#*#
|
||||
*~
|
||||
.cpplint-cache
|
||||
|
||||
31
deps/v8/ChangeLog
vendored
31
deps/v8/ChangeLog
vendored
@@ -1,3 +1,14 @@
|
||||
2011-09-08: Version 3.6.2
|
||||
|
||||
Added "dependencies" target to top-level Makefile.
|
||||
|
||||
Added ability to turn profiler on/off in d8.
|
||||
|
||||
Added "soname_version" parameter to common.gypi, v8.gyp, and Makefile.
|
||||
|
||||
Fixed several crash bugs.
|
||||
|
||||
|
||||
2011-09-07: Version 3.6.1
|
||||
|
||||
Fixed a bug in abrupt exit from with or catch inside finally.
|
||||
@@ -14,23 +25,23 @@
|
||||
|
||||
2011-09-05: Version 3.6.0
|
||||
|
||||
Fixed a bug when optimizing named function expression (issue 1647).
|
||||
Fixed a bug when optimizing named function expression (issue 1647).
|
||||
|
||||
Fixed a bug when optimizing f.call.apply (issue 1650).
|
||||
Fixed a bug when optimizing f.call.apply (issue 1650).
|
||||
|
||||
Made arguments and caller always be null on native functions
|
||||
(issues 1548 and 1643).
|
||||
Made arguments and caller always be null on native functions
|
||||
(issues 1548 and 1643).
|
||||
|
||||
Fixed issue 1648 (cross-compiling x64 targeting ia32).
|
||||
Fixed issue 1648 (cross-compiling x64 targeting ia32).
|
||||
|
||||
Fixed issue 371 (d8 printing of strings containing \0).
|
||||
Fixed issue 371 (d8 printing of strings containing \0).
|
||||
|
||||
Fixed order of evaluation in arguments to parseInt (issue 1649).
|
||||
Fixed order of evaluation in arguments to parseInt (issue 1649).
|
||||
|
||||
Fixed a problem with large heap snapshots in Chrome DevTools
|
||||
(issue 1658, chromium issue 89268).
|
||||
Fixed a problem with large heap snapshots in Chrome DevTools
|
||||
(issue 1658, chromium issue 89268).
|
||||
|
||||
Upped default maximum heap size from 512M to 700M.
|
||||
Upped default maximum heap size from 512M to 700M.
|
||||
|
||||
|
||||
2011-08-31: Version 3.5.10
|
||||
|
||||
12
deps/v8/Makefile
vendored
12
deps/v8/Makefile
vendored
@@ -68,8 +68,13 @@ ifeq ($(vfp3), off)
|
||||
else
|
||||
GYPFLAGS += -Dv8_can_use_vfp_instructions=true
|
||||
endif
|
||||
# soname_version=1.2.3
|
||||
ifdef soname_version
|
||||
GYPFLAGS += -Dsoname_version=$(soname_version)
|
||||
endif
|
||||
|
||||
# ----------------- available targets: --------------------
|
||||
# - "dependencies": pulls in external dependencies (currently: GYP)
|
||||
# - any arch listed in ARCHES (see below)
|
||||
# - any mode listed in MODES
|
||||
# - every combination <arch>.<mode>, e.g. "ia32.release"
|
||||
@@ -98,7 +103,7 @@ CHECKS = $(addsuffix .check,$(BUILDS))
|
||||
# File where previously used GYPFLAGS are stored.
|
||||
ENVFILE = $(OUTDIR)/environment
|
||||
|
||||
.PHONY: all check clean $(ENVFILE).new \
|
||||
.PHONY: all check clean dependencies $(ENVFILE).new \
|
||||
$(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \
|
||||
$(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES))
|
||||
|
||||
@@ -170,3 +175,8 @@ $(ENVFILE): $(ENVFILE).new
|
||||
# Stores current GYPFLAGS in a file.
|
||||
$(ENVFILE).new:
|
||||
@mkdir -p $(OUTDIR); echo "GYPFLAGS=$(GYPFLAGS)" > $(ENVFILE).new;
|
||||
|
||||
# Dependencies.
|
||||
dependencies:
|
||||
svn checkout --force http://gyp.googlecode.com/svn/trunk build/gyp \
|
||||
--revision 1026
|
||||
|
||||
3
deps/v8/build/common.gypi
vendored
3
deps/v8/build/common.gypi
vendored
@@ -72,6 +72,9 @@
|
||||
'v8_use_snapshot%': 'true',
|
||||
'host_os%': '<(OS)',
|
||||
'v8_use_liveobjectlist%': 'false',
|
||||
|
||||
# For a shared library build, results in "libv8-<(soname_version).so".
|
||||
'soname_version%': '',
|
||||
},
|
||||
'target_defaults': {
|
||||
'conditions': [
|
||||
|
||||
18
deps/v8/src/SConscript
vendored
18
deps/v8/src/SConscript
vendored
@@ -111,8 +111,8 @@ SOURCES = {
|
||||
runtime.cc
|
||||
runtime-profiler.cc
|
||||
safepoint-table.cc
|
||||
scanner-base.cc
|
||||
scanner.cc
|
||||
scanner-character-streams.cc
|
||||
scopeinfo.cc
|
||||
scopes.cc
|
||||
serialize.cc
|
||||
@@ -222,7 +222,7 @@ SOURCES = {
|
||||
'os:solaris': ['platform-solaris.cc', 'platform-posix.cc'],
|
||||
'os:cygwin': ['platform-cygwin.cc', 'platform-posix.cc'],
|
||||
'os:nullos': ['platform-nullos.cc'],
|
||||
'os:win32': ['platform-win32.cc'],
|
||||
'os:win32': ['platform-win32.cc', 'win32-math.cc'],
|
||||
'mode:release': [],
|
||||
'mode:debug': [
|
||||
'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
|
||||
@@ -233,15 +233,25 @@ SOURCES = {
|
||||
PREPARSER_SOURCES = {
|
||||
'all': Split("""
|
||||
allocation.cc
|
||||
bignum.cc
|
||||
bignum-dtoa.cc
|
||||
cached-powers.cc
|
||||
conversions.cc
|
||||
diy-fp.cc
|
||||
dtoa.cc
|
||||
fast-dtoa.cc
|
||||
fixed-dtoa.cc
|
||||
hashmap.cc
|
||||
preparse-data.cc
|
||||
preparser.cc
|
||||
preparser-api.cc
|
||||
scanner-base.cc
|
||||
scanner.cc
|
||||
strtod.cc
|
||||
token.cc
|
||||
unicode.cc
|
||||
utils.cc
|
||||
""")
|
||||
"""),
|
||||
'os:win32': ['win32-math.cc']
|
||||
}
|
||||
|
||||
|
||||
|
||||
1
deps/v8/src/api.cc
vendored
1
deps/v8/src/api.cc
vendored
@@ -44,6 +44,7 @@
|
||||
#include "platform.h"
|
||||
#include "profile-generator-inl.h"
|
||||
#include "runtime-profiler.h"
|
||||
#include "scanner-character-streams.h"
|
||||
#include "serialize.h"
|
||||
#include "snapshot.h"
|
||||
#include "v8threads.h"
|
||||
|
||||
5
deps/v8/src/ast.cc
vendored
5
deps/v8/src/ast.cc
vendored
@@ -404,11 +404,6 @@ bool WithStatement::IsInlineable() const {
|
||||
}
|
||||
|
||||
|
||||
bool ExitContextStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SwitchStatement::IsInlineable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
9
deps/v8/src/ast.h
vendored
9
deps/v8/src/ast.h
vendored
@@ -62,7 +62,6 @@ namespace internal {
|
||||
V(BreakStatement) \
|
||||
V(ReturnStatement) \
|
||||
V(WithStatement) \
|
||||
V(ExitContextStatement) \
|
||||
V(SwitchStatement) \
|
||||
V(DoWhileStatement) \
|
||||
V(WhileStatement) \
|
||||
@@ -681,14 +680,6 @@ class WithStatement: public Statement {
|
||||
};
|
||||
|
||||
|
||||
class ExitContextStatement: public Statement {
|
||||
public:
|
||||
virtual bool IsInlineable() const;
|
||||
|
||||
DECLARE_NODE_TYPE(ExitContextStatement)
|
||||
};
|
||||
|
||||
|
||||
class CaseClause: public ZoneObject {
|
||||
public:
|
||||
CaseClause(Isolate* isolate,
|
||||
|
||||
7
deps/v8/src/bignum-dtoa.cc
vendored
7
deps/v8/src/bignum-dtoa.cc
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Copyright 2011 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:
|
||||
@@ -27,7 +27,10 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "v8.h"
|
||||
#include "../include/v8stdint.h"
|
||||
#include "checks.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "bignum-dtoa.h"
|
||||
|
||||
#include "bignum.h"
|
||||
|
||||
1
deps/v8/src/compiler.cc
vendored
1
deps/v8/src/compiler.cc
vendored
@@ -41,6 +41,7 @@
|
||||
#include "parser.h"
|
||||
#include "rewriter.h"
|
||||
#include "runtime-profiler.h"
|
||||
#include "scanner-character-streams.h"
|
||||
#include "scopeinfo.h"
|
||||
#include "scopes.h"
|
||||
#include "vm-state-inl.h"
|
||||
|
||||
20
deps/v8/src/conversions-inl.h
vendored
20
deps/v8/src/conversions-inl.h
vendored
@@ -32,13 +32,16 @@
|
||||
#include <math.h>
|
||||
#include <float.h> // Required for DBL_MAX and on Win32 for finite()
|
||||
#include <stdarg.h>
|
||||
#include "globals.h" // Required for V8_INFINITY
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extra POSIX/ANSI functions for Win32/MSVC.
|
||||
|
||||
#include "conversions.h"
|
||||
#include "strtod.h"
|
||||
#include "double.h"
|
||||
#include "platform.h"
|
||||
#include "scanner.h"
|
||||
#include "strtod.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@@ -87,12 +90,15 @@ static inline double DoubleToInteger(double x) {
|
||||
int32_t DoubleToInt32(double x) {
|
||||
int32_t i = FastD2I(x);
|
||||
if (FastI2D(i) == x) return i;
|
||||
static const double two32 = 4294967296.0;
|
||||
static const double two31 = 2147483648.0;
|
||||
if (!isfinite(x) || x == 0) return 0;
|
||||
if (x < 0 || x >= two32) x = modulo(x, two32);
|
||||
x = (x >= 0) ? floor(x) : ceil(x) + two32;
|
||||
return (int32_t) ((x >= two31) ? x - two32 : x);
|
||||
Double d(x);
|
||||
int exponent = d.Exponent();
|
||||
if (exponent < 0) {
|
||||
if (exponent <= -Double::kSignificandSize) return 0;
|
||||
return d.Sign() * static_cast<int32_t>(d.Significand() >> -exponent);
|
||||
} else {
|
||||
if (exponent > 31) return 0;
|
||||
return d.Sign() * static_cast<int32_t>(d.Significand() << exponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
5
deps/v8/src/conversions.cc
vendored
5
deps/v8/src/conversions.cc
vendored
@@ -26,11 +26,11 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "conversions-inl.h"
|
||||
#include "dtoa.h"
|
||||
#include "scanner-base.h"
|
||||
#include "strtod.h"
|
||||
#include "utils.h"
|
||||
|
||||
@@ -38,7 +38,6 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
|
||||
double StringToDouble(UnicodeCache* unicode_cache,
|
||||
const char* str, int flags, double empty_string_val) {
|
||||
const char* end = str + StrLength(str);
|
||||
@@ -390,7 +389,7 @@ char* DoubleToRadixCString(double value, int radix) {
|
||||
int integer_pos = kBufferSize - 2;
|
||||
do {
|
||||
integer_buffer[integer_pos--] =
|
||||
chars[static_cast<int>(modulo(integer_part, radix))];
|
||||
chars[static_cast<int>(fmod(integer_part, radix))];
|
||||
integer_part /= radix;
|
||||
} while (integer_part >= 1.0);
|
||||
// Sanity check.
|
||||
|
||||
6
deps/v8/src/conversions.h
vendored
6
deps/v8/src/conversions.h
vendored
@@ -30,11 +30,13 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "scanner-base.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class UnicodeCache;
|
||||
|
||||
// Maximum number of significant digits in decimal representation.
|
||||
// The longest possible double in decimal representation is
|
||||
// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
|
||||
@@ -125,6 +127,8 @@ double StringToDouble(UnicodeCache* unicode_cache,
|
||||
int flags,
|
||||
double empty_string_val = 0);
|
||||
|
||||
const int kDoubleToCStringMinBufferSize = 100;
|
||||
|
||||
// Converts a double to a string value according to ECMA-262 9.8.1.
|
||||
// The buffer should be large enough for any floating point number.
|
||||
// 100 characters is enough.
|
||||
|
||||
27
deps/v8/src/d8.cc
vendored
27
deps/v8/src/d8.cc
vendored
@@ -210,6 +210,18 @@ Handle<Value> Shell::Write(const Arguments& args) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Value> Shell::EnableProfiler(const Arguments& args) {
|
||||
V8::ResumeProfiler();
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
|
||||
Handle<Value> Shell::DisableProfiler(const Arguments& args) {
|
||||
V8::PauseProfiler();
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
|
||||
Handle<Value> Shell::Read(const Arguments& args) {
|
||||
String::Utf8Value file(args[0]);
|
||||
if (*file == NULL) {
|
||||
@@ -656,6 +668,10 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
|
||||
global_template->Set(String::New("load"), FunctionTemplate::New(Load));
|
||||
global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
|
||||
global_template->Set(String::New("version"), FunctionTemplate::New(Version));
|
||||
global_template->Set(String::New("enableProfiler"),
|
||||
FunctionTemplate::New(EnableProfiler));
|
||||
global_template->Set(String::New("disableProfiler"),
|
||||
FunctionTemplate::New(DisableProfiler));
|
||||
|
||||
// Bind the handlers for external arrays.
|
||||
global_template->Set(String::New("Int8Array"),
|
||||
@@ -1021,7 +1037,7 @@ i::Thread::Options SourceGroup::GetThreadOptions() {
|
||||
void SourceGroup::ExecuteInThread() {
|
||||
Isolate* isolate = Isolate::New();
|
||||
do {
|
||||
if (next_semaphore_ != NULL) next_semaphore_->Wait();
|
||||
if (!next_semaphore_.is_empty()) next_semaphore_->Wait();
|
||||
{
|
||||
Isolate::Scope iscope(isolate);
|
||||
Locker lock(isolate);
|
||||
@@ -1033,15 +1049,15 @@ void SourceGroup::ExecuteInThread() {
|
||||
}
|
||||
context.Dispose();
|
||||
}
|
||||
if (done_semaphore_ != NULL) done_semaphore_->Signal();
|
||||
if (!done_semaphore_.is_empty()) done_semaphore_->Signal();
|
||||
} while (!Shell::options.last_run);
|
||||
isolate->Dispose();
|
||||
}
|
||||
|
||||
|
||||
void SourceGroup::StartExecuteInThread() {
|
||||
if (thread_ == NULL) {
|
||||
thread_ = new IsolateThread(this);
|
||||
if (thread_.is_empty()) {
|
||||
thread_ = i::SmartPointer<i::Thread>(new IsolateThread(this));
|
||||
thread_->Start();
|
||||
}
|
||||
next_semaphore_->Signal();
|
||||
@@ -1049,10 +1065,9 @@ void SourceGroup::StartExecuteInThread() {
|
||||
|
||||
|
||||
void SourceGroup::WaitForThread() {
|
||||
if (thread_ == NULL) return;
|
||||
if (thread_.is_empty()) return;
|
||||
if (Shell::options.last_run) {
|
||||
thread_->Join();
|
||||
thread_ = NULL;
|
||||
} else {
|
||||
done_semaphore_->Wait();
|
||||
}
|
||||
|
||||
15
deps/v8/src/d8.h
vendored
15
deps/v8/src/d8.h
vendored
@@ -28,11 +28,11 @@
|
||||
#ifndef V8_D8_H_
|
||||
#define V8_D8_H_
|
||||
|
||||
|
||||
#ifndef V8_SHARED
|
||||
#include "v8.h"
|
||||
#include "allocation.h"
|
||||
#include "hashmap.h"
|
||||
#include "smart-pointer.h"
|
||||
#include "v8.h"
|
||||
#else
|
||||
#include "../include/v8.h"
|
||||
#endif // V8_SHARED
|
||||
@@ -122,11 +122,10 @@ class SourceGroup {
|
||||
#ifndef V8_SHARED
|
||||
next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
|
||||
done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
|
||||
thread_(NULL),
|
||||
#endif // V8_SHARED
|
||||
argv_(NULL),
|
||||
begin_offset_(0),
|
||||
end_offset_(0) { }
|
||||
end_offset_(0) {}
|
||||
|
||||
void Begin(char** argv, int offset) {
|
||||
argv_ = const_cast<const char**>(argv);
|
||||
@@ -158,9 +157,9 @@ class SourceGroup {
|
||||
static i::Thread::Options GetThreadOptions();
|
||||
void ExecuteInThread();
|
||||
|
||||
i::Semaphore* next_semaphore_;
|
||||
i::Semaphore* done_semaphore_;
|
||||
i::Thread* thread_;
|
||||
i::SmartPointer<i::Semaphore> next_semaphore_;
|
||||
i::SmartPointer<i::Semaphore> done_semaphore_;
|
||||
i::SmartPointer<i::Thread> thread_;
|
||||
#endif // V8_SHARED
|
||||
|
||||
void ExitShell(int exit_code);
|
||||
@@ -248,6 +247,8 @@ class Shell : public i::AllStatic {
|
||||
static Handle<Value> Yield(const Arguments& args);
|
||||
static Handle<Value> Quit(const Arguments& args);
|
||||
static Handle<Value> Version(const Arguments& args);
|
||||
static Handle<Value> EnableProfiler(const Arguments& args);
|
||||
static Handle<Value> DisableProfiler(const Arguments& args);
|
||||
static Handle<Value> Read(const Arguments& args);
|
||||
static Handle<Value> ReadLine(const Arguments& args);
|
||||
static Handle<Value> Load(const Arguments& args);
|
||||
|
||||
1
deps/v8/src/dateparser.h
vendored
1
deps/v8/src/dateparser.h
vendored
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "allocation.h"
|
||||
#include "char-predicates-inl.h"
|
||||
#include "scanner-base.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
7
deps/v8/src/dtoa.cc
vendored
7
deps/v8/src/dtoa.cc
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Copyright 2011 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:
|
||||
@@ -27,7 +27,10 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "v8.h"
|
||||
#include "../include/v8stdint.h"
|
||||
#include "checks.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "dtoa.h"
|
||||
|
||||
#include "bignum-dtoa.h"
|
||||
|
||||
6
deps/v8/src/fast-dtoa.cc
vendored
6
deps/v8/src/fast-dtoa.cc
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Copyright 2011 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:
|
||||
@@ -25,7 +25,9 @@
|
||||
// (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 "v8.h"
|
||||
#include "../include/v8stdint.h"
|
||||
#include "checks.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "fast-dtoa.h"
|
||||
|
||||
|
||||
6
deps/v8/src/fixed-dtoa.cc
vendored
6
deps/v8/src/fixed-dtoa.cc
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Copyright 2011 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:
|
||||
@@ -27,7 +27,9 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "v8.h"
|
||||
#include "../include/v8stdint.h"
|
||||
#include "checks.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "double.h"
|
||||
#include "fixed-dtoa.h"
|
||||
|
||||
19
deps/v8/src/full-codegen.cc
vendored
19
deps/v8/src/full-codegen.cc
vendored
@@ -96,11 +96,6 @@ void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void BreakableStatementChecker::VisitExitContextStatement(
|
||||
ExitContextStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
|
||||
// Switch statements breakable if the tag expression is.
|
||||
Visit(stmt->tag());
|
||||
@@ -989,17 +984,6 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitExitContextStatement(ExitContextStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ ExitContextStatement");
|
||||
SetStatementPosition(stmt);
|
||||
|
||||
// Pop context.
|
||||
LoadContextField(context_register(), Context::PREVIOUS_INDEX);
|
||||
// Update local stack frame context field.
|
||||
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
||||
Comment cmnt(masm_, "[ DoWhileStatement");
|
||||
SetStatementPosition(stmt);
|
||||
@@ -1147,6 +1131,9 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
||||
{ WithOrCatch body(this);
|
||||
Visit(stmt->catch_block());
|
||||
}
|
||||
// Restore the context.
|
||||
LoadContextField(context_register(), Context::PREVIOUS_INDEX);
|
||||
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
|
||||
scope_ = saved_scope;
|
||||
__ jmp(&done);
|
||||
|
||||
|
||||
29
deps/v8/src/globals.h
vendored
29
deps/v8/src/globals.h
vendored
@@ -28,6 +28,35 @@
|
||||
#ifndef V8_GLOBALS_H_
|
||||
#define V8_GLOBALS_H_
|
||||
|
||||
// Define V8_INFINITY
|
||||
#define V8_INFINITY INFINITY
|
||||
|
||||
// GCC specific stuff
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define __GNUC_VERSION_FOR_INFTY__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
|
||||
|
||||
// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
|
||||
// warning flag and certain versions of GCC due to a bug:
|
||||
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
|
||||
// For now, we use the more involved template-based version from <limits>, but
|
||||
// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
|
||||
// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
|
||||
#if __GNUC_VERSION_FOR_INFTY__ >= 29600 && __GNUC_VERSION_FOR_INFTY__ < 40100
|
||||
#include <limits>
|
||||
#undef V8_INFINITY
|
||||
#define V8_INFINITY std::numeric_limits<double>::infinity()
|
||||
#endif
|
||||
#undef __GNUC_VERSION_FOR_INFTY__
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#undef V8_INFINITY
|
||||
#define V8_INFINITY HUGE_VAL
|
||||
#endif
|
||||
|
||||
|
||||
#include "../include/v8stdint.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
44
deps/v8/src/heap.cc
vendored
44
deps/v8/src/heap.cc
vendored
@@ -41,7 +41,6 @@
|
||||
#include "natives.h"
|
||||
#include "objects-visiting.h"
|
||||
#include "runtime-profiler.h"
|
||||
#include "scanner-base.h"
|
||||
#include "scopeinfo.h"
|
||||
#include "snapshot.h"
|
||||
#include "v8threads.h"
|
||||
@@ -2259,8 +2258,8 @@ bool Heap::CreateInitialObjects() {
|
||||
Object* StringSplitCache::Lookup(
|
||||
FixedArray* cache, String* string, String* pattern) {
|
||||
if (!string->IsSymbol() || !pattern->IsSymbol()) return Smi::FromInt(0);
|
||||
uintptr_t hash = string->Hash();
|
||||
uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) &
|
||||
uint32_t hash = string->Hash();
|
||||
uint32_t index = ((hash & (kStringSplitCacheSize - 1)) &
|
||||
~(kArrayEntriesPerCacheEntry - 1));
|
||||
if (cache->get(index + kStringOffset) == string &&
|
||||
cache->get(index + kPatternOffset) == pattern) {
|
||||
@@ -2281,30 +2280,29 @@ void StringSplitCache::Enter(Heap* heap,
|
||||
String* pattern,
|
||||
FixedArray* array) {
|
||||
if (!string->IsSymbol() || !pattern->IsSymbol()) return;
|
||||
uintptr_t hash = string->Hash();
|
||||
array->set_map(heap->fixed_cow_array_map());
|
||||
uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) &
|
||||
uint32_t hash = string->Hash();
|
||||
uint32_t index = ((hash & (kStringSplitCacheSize - 1)) &
|
||||
~(kArrayEntriesPerCacheEntry - 1));
|
||||
if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
|
||||
cache->set(index + kStringOffset, string);
|
||||
cache->set(index + kPatternOffset, pattern);
|
||||
cache->set(index + kArrayOffset, array);
|
||||
return;
|
||||
} else {
|
||||
uint32_t index2 =
|
||||
((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
|
||||
if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
|
||||
cache->set(index2 + kStringOffset, string);
|
||||
cache->set(index2 + kPatternOffset, pattern);
|
||||
cache->set(index2 + kArrayOffset, array);
|
||||
} else {
|
||||
cache->set(index2 + kStringOffset, Smi::FromInt(0));
|
||||
cache->set(index2 + kPatternOffset, Smi::FromInt(0));
|
||||
cache->set(index2 + kArrayOffset, Smi::FromInt(0));
|
||||
cache->set(index + kStringOffset, string);
|
||||
cache->set(index + kPatternOffset, pattern);
|
||||
cache->set(index + kArrayOffset, array);
|
||||
}
|
||||
}
|
||||
uintptr_t index2 =
|
||||
((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
|
||||
if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
|
||||
cache->set(index2 + kStringOffset, string);
|
||||
cache->set(index2 + kPatternOffset, pattern);
|
||||
cache->set(index2 + kArrayOffset, array);
|
||||
return;
|
||||
}
|
||||
cache->set(index2 + kStringOffset, Smi::FromInt(0));
|
||||
cache->set(index2 + kPatternOffset, Smi::FromInt(0));
|
||||
cache->set(index2 + kArrayOffset, Smi::FromInt(0));
|
||||
cache->set(index + kStringOffset, string);
|
||||
cache->set(index + kPatternOffset, pattern);
|
||||
cache->set(index + kArrayOffset, array);
|
||||
if (array->length() < 100) { // Limit how many new symbols we want to make.
|
||||
for (int i = 0; i < array->length(); i++) {
|
||||
String* str = String::cast(array->get(i));
|
||||
@@ -2315,6 +2313,7 @@ void StringSplitCache::Enter(Heap* heap,
|
||||
}
|
||||
}
|
||||
}
|
||||
array->set_map(heap->fixed_cow_array_map());
|
||||
}
|
||||
|
||||
|
||||
@@ -3623,6 +3622,9 @@ MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
|
||||
|
||||
MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string,
|
||||
PretenureFlag pretenure) {
|
||||
if (string.length() == 1) {
|
||||
return Heap::LookupSingleCharacterStringFromCode(string[0]);
|
||||
}
|
||||
Object* result;
|
||||
{ MaybeObject* maybe_result =
|
||||
AllocateRawAsciiString(string.length(), pretenure);
|
||||
|
||||
12
deps/v8/src/hydrogen.cc
vendored
12
deps/v8/src/hydrogen.cc
vendored
@@ -1675,7 +1675,9 @@ void HInferRepresentation::Analyze() {
|
||||
bool change = true;
|
||||
while (change) {
|
||||
change = false;
|
||||
for (int i = 0; i < phi_count; ++i) {
|
||||
// We normally have far more "forward edges" than "backward edges",
|
||||
// so we terminate faster when we walk backwards.
|
||||
for (int i = phi_count - 1; i >= 0; --i) {
|
||||
HPhi* phi = phi_list->at(i);
|
||||
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
|
||||
HValue* use = it.value();
|
||||
@@ -2652,14 +2654,6 @@ void HGraphBuilder::VisitWithStatement(WithStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
ASSERT(current_block()->HasPredecessor());
|
||||
return Bailout("ExitContextStatement");
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
||||
ASSERT(!HasStackOverflow());
|
||||
ASSERT(current_block() != NULL);
|
||||
|
||||
1
deps/v8/src/isolate.cc
vendored
1
deps/v8/src/isolate.cc
vendored
@@ -43,7 +43,6 @@
|
||||
#include "messages.h"
|
||||
#include "regexp-stack.h"
|
||||
#include "runtime-profiler.h"
|
||||
#include "scanner.h"
|
||||
#include "scopeinfo.h"
|
||||
#include "serialize.h"
|
||||
#include "simulator.h"
|
||||
|
||||
625
deps/v8/src/mips/full-codegen-mips.cc
vendored
625
deps/v8/src/mips/full-codegen-mips.cc
vendored
@@ -200,14 +200,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
// Copy any necessary parameters into the context.
|
||||
int num_parameters = info->scope()->num_parameters();
|
||||
for (int i = 0; i < num_parameters; i++) {
|
||||
Slot* slot = scope()->parameter(i)->rewrite();
|
||||
if (slot != NULL && slot->type() == Slot::CONTEXT) {
|
||||
Variable* var = scope()->parameter(i);
|
||||
if (var->IsContextSlot()) {
|
||||
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
||||
(num_parameters - 1 - i) * kPointerSize;
|
||||
// Load parameter from stack.
|
||||
__ lw(a0, MemOperand(fp, parameter_offset));
|
||||
// Store it in the context.
|
||||
__ li(a1, Operand(Context::SlotOffset(slot->index())));
|
||||
__ li(a1, Operand(Context::SlotOffset(var->index())));
|
||||
__ addu(a2, cp, a1);
|
||||
__ sw(a0, MemOperand(a2, 0));
|
||||
// Update the write barrier. This clobbers all involved
|
||||
@@ -252,7 +252,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
ArgumentsAccessStub stub(type);
|
||||
__ CallStub(&stub);
|
||||
|
||||
Move(arguments->rewrite(), v0, a1, a2);
|
||||
SetVar(arguments, v0, a1, a2);
|
||||
}
|
||||
|
||||
if (FLAG_trace) {
|
||||
@@ -271,7 +271,8 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
|
||||
// For named function expressions, declare the function name as a
|
||||
// constant.
|
||||
if (scope()->is_function_scope() && scope()->function() != NULL) {
|
||||
EmitDeclaration(scope()->function(), Variable::CONST, NULL);
|
||||
int ignored = 0;
|
||||
EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
|
||||
}
|
||||
VisitDeclarations(scope()->declarations());
|
||||
}
|
||||
@@ -371,24 +372,27 @@ void FullCodeGenerator::EmitReturnSequence() {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
|
||||
void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
|
||||
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
|
||||
codegen()->Move(result_register(), slot);
|
||||
void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
|
||||
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
|
||||
codegen()->GetVar(result_register(), var);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
|
||||
codegen()->Move(result_register(), slot);
|
||||
void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
|
||||
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
|
||||
codegen()->GetVar(result_register(), var);
|
||||
__ push(result_register());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
|
||||
void FullCodeGenerator::TestContext::Plug(Variable* var) const {
|
||||
// For simplicity we always test the accumulator register.
|
||||
codegen()->Move(result_register(), slot);
|
||||
codegen()->GetVar(result_register(), var);
|
||||
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
||||
codegen()->DoTest(this);
|
||||
}
|
||||
@@ -621,30 +625,56 @@ void FullCodeGenerator::Split(Condition cc,
|
||||
}
|
||||
|
||||
|
||||
MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
return MemOperand(fp, SlotOffset(slot));
|
||||
case Slot::CONTEXT: {
|
||||
int context_chain_length =
|
||||
scope()->ContextChainLength(slot->var()->scope());
|
||||
__ LoadContext(scratch, context_chain_length);
|
||||
return ContextOperand(scratch, slot->index());
|
||||
}
|
||||
case Slot::LOOKUP:
|
||||
case Slot::GLOBAL:
|
||||
UNREACHABLE();
|
||||
MemOperand FullCodeGenerator::StackOperand(Variable* var) {
|
||||
ASSERT(var->IsStackAllocated());
|
||||
// Offset is negative because higher indexes are at lower addresses.
|
||||
int offset = -var->index() * kPointerSize;
|
||||
// Adjust by a (parameter or local) base offset.
|
||||
if (var->IsParameter()) {
|
||||
offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
|
||||
} else {
|
||||
offset += JavaScriptFrameConstants::kLocal0Offset;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return MemOperand(v0, 0);
|
||||
return MemOperand(fp, offset);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::Move(Register destination, Slot* source) {
|
||||
MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
|
||||
ASSERT(var->IsContextSlot() || var->IsStackAllocated());
|
||||
if (var->IsContextSlot()) {
|
||||
int context_chain_length = scope()->ContextChainLength(var->scope());
|
||||
__ LoadContext(scratch, context_chain_length);
|
||||
return ContextOperand(scratch, var->index());
|
||||
} else {
|
||||
return StackOperand(var);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::GetVar(Register dest, Variable* var) {
|
||||
// Use destination as scratch.
|
||||
MemOperand slot_operand = EmitSlotSearch(source, destination);
|
||||
__ lw(destination, slot_operand);
|
||||
MemOperand location = VarOperand(var, dest);
|
||||
__ lw(dest, location);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::SetVar(Variable* var,
|
||||
Register src,
|
||||
Register scratch0,
|
||||
Register scratch1) {
|
||||
ASSERT(var->IsContextSlot() || var->IsStackAllocated());
|
||||
ASSERT(!scratch0.is(src));
|
||||
ASSERT(!scratch0.is(scratch1));
|
||||
ASSERT(!scratch1.is(src));
|
||||
MemOperand location = VarOperand(var, scratch0);
|
||||
__ sw(src, location);
|
||||
// Emit the write barrier code if the location is in the heap.
|
||||
if (var->IsContextSlot()) {
|
||||
__ RecordWrite(scratch0,
|
||||
Operand(Context::SlotOffset(var->index())),
|
||||
scratch1,
|
||||
src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -674,48 +704,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::Move(Slot* dst,
|
||||
Register src,
|
||||
Register scratch1,
|
||||
Register scratch2) {
|
||||
ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
|
||||
ASSERT(!scratch1.is(src) && !scratch2.is(src));
|
||||
MemOperand location = EmitSlotSearch(dst, scratch1);
|
||||
__ sw(src, location);
|
||||
// Emit the write barrier code if the location is in the heap.
|
||||
if (dst->type() == Slot::CONTEXT) {
|
||||
__ RecordWrite(scratch1,
|
||||
Operand(Context::SlotOffset(dst->index())),
|
||||
scratch2,
|
||||
src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
|
||||
Variable::Mode mode,
|
||||
FunctionLiteral* function) {
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
FunctionLiteral* function,
|
||||
int* global_count) {
|
||||
// If it was not possible to allocate the variable at compile time, we
|
||||
// need to "declare" it at runtime to make sure it actually exists in the
|
||||
// local context.
|
||||
Variable* variable = proxy->var();
|
||||
ASSERT(variable != NULL); // Must have been resolved.
|
||||
Slot* slot = variable->rewrite();
|
||||
ASSERT(slot != NULL);
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
switch (variable->location()) {
|
||||
case Variable::UNALLOCATED:
|
||||
++(*global_count);
|
||||
break;
|
||||
|
||||
case Variable::PARAMETER:
|
||||
case Variable::LOCAL:
|
||||
if (function != NULL) {
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
VisitForAccumulatorValue(function);
|
||||
__ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
__ sw(result_register(), StackOperand(variable));
|
||||
} else if (mode == Variable::CONST || mode == Variable::LET) {
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ sw(t0, MemOperand(fp, SlotOffset(slot)));
|
||||
__ sw(t0, StackOperand(variable));
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::CONTEXT:
|
||||
// We bypass the general EmitSlotSearch because we know more about
|
||||
// this specific context.
|
||||
|
||||
case Variable::CONTEXT:
|
||||
// The variable in the decl always resides in the current function
|
||||
// context.
|
||||
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
|
||||
@@ -730,24 +745,27 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
|
||||
a1, Operand(t0));
|
||||
}
|
||||
if (function != NULL) {
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
VisitForAccumulatorValue(function);
|
||||
__ sw(result_register(), ContextOperand(cp, slot->index()));
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
__ sw(result_register(), ContextOperand(cp, variable->index()));
|
||||
int offset = Context::SlotOffset(variable->index());
|
||||
// We know that we have written a function, which is not a smi.
|
||||
__ mov(a1, cp);
|
||||
__ RecordWrite(a1, Operand(offset), a2, result_register());
|
||||
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
|
||||
} else if (mode == Variable::CONST || mode == Variable::LET) {
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
__ sw(at, ContextOperand(cp, slot->index()));
|
||||
__ sw(at, ContextOperand(cp, variable->index()));
|
||||
// No write barrier since the_hole_value is in old space.
|
||||
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
|
||||
}
|
||||
break;
|
||||
|
||||
case Slot::LOOKUP: {
|
||||
case Variable::LOOKUP: {
|
||||
Comment cmnt(masm_, "[ Declaration");
|
||||
__ li(a2, Operand(variable->name()));
|
||||
// Declaration nodes are always introduced in one of two modes.
|
||||
// Declaration nodes are always introduced in one of three modes.
|
||||
ASSERT(mode == Variable::VAR ||
|
||||
mode == Variable::CONST ||
|
||||
mode == Variable::LET);
|
||||
@@ -766,23 +784,17 @@ void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
|
||||
__ Push(cp, a2, a1, a0);
|
||||
} else {
|
||||
ASSERT(Smi::FromInt(0) == 0);
|
||||
// No initial value!
|
||||
__ mov(a0, zero_reg); // Operand(Smi::FromInt(0)));
|
||||
__ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value.
|
||||
__ Push(cp, a2, a1, a0);
|
||||
}
|
||||
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case Slot::GLOBAL:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
|
||||
EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
|
||||
}
|
||||
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
|
||||
|
||||
|
||||
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
|
||||
@@ -1095,10 +1107,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
Label* slow) {
|
||||
void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
|
||||
TypeofState typeof_state,
|
||||
Label* slow) {
|
||||
Register current = cp;
|
||||
Register next = a1;
|
||||
Register temp = a2;
|
||||
@@ -1142,7 +1153,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
}
|
||||
|
||||
__ lw(a0, GlobalObjectOperand());
|
||||
__ li(a2, Operand(slot->var()->name()));
|
||||
__ li(a2, Operand(var->name()));
|
||||
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
|
||||
? RelocInfo::CODE_TARGET
|
||||
: RelocInfo::CODE_TARGET_CONTEXT;
|
||||
@@ -1151,15 +1162,14 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
|
||||
}
|
||||
|
||||
|
||||
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
|
||||
Slot* slot,
|
||||
Label* slow) {
|
||||
ASSERT(slot->type() == Slot::CONTEXT);
|
||||
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
|
||||
Label* slow) {
|
||||
ASSERT(var->IsContextSlot());
|
||||
Register context = cp;
|
||||
Register next = a3;
|
||||
Register temp = t0;
|
||||
|
||||
for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
|
||||
for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
|
||||
if (s->num_heap_slots() > 0) {
|
||||
if (s->calls_eval()) {
|
||||
// Check that extension is NULL.
|
||||
@@ -1178,60 +1188,32 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
|
||||
// This function is used only for loads, not stores, so it's safe to
|
||||
// return an cp-based operand (the write barrier cannot be allowed to
|
||||
// destroy the cp register).
|
||||
return ContextOperand(context, slot->index());
|
||||
return ContextOperand(context, var->index());
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
|
||||
Slot* slot,
|
||||
TypeofState typeof_state,
|
||||
Label* slow,
|
||||
Label* done) {
|
||||
void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
|
||||
TypeofState typeof_state,
|
||||
Label* slow,
|
||||
Label* done) {
|
||||
// Generate fast-case code for variables that might be shadowed by
|
||||
// eval-introduced variables. Eval is used a lot without
|
||||
// introducing variables. In those cases, we do not want to
|
||||
// perform a runtime call for all variables in the scope
|
||||
// containing the eval.
|
||||
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
|
||||
if (var->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
|
||||
__ Branch(done);
|
||||
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
|
||||
Slot* potential_slot = slot->var()->local_if_not_shadowed()->rewrite();
|
||||
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
|
||||
if (potential_slot != NULL) {
|
||||
// Generate fast case for locals that rewrite to slots.
|
||||
__ lw(v0, ContextSlotOperandCheckExtensions(potential_slot, slow));
|
||||
if (potential_slot->var()->mode() == Variable::CONST) {
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
__ subu(at, v0, at); // Sub as compare: at == 0 on eq.
|
||||
__ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
|
||||
__ movz(v0, a0, at); // Conditional move.
|
||||
}
|
||||
__ Branch(done);
|
||||
} else if (rewrite != NULL) {
|
||||
// Generate fast case for calls of an argument function.
|
||||
Property* property = rewrite->AsProperty();
|
||||
if (property != NULL) {
|
||||
VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
||||
Literal* key_literal = property->key()->AsLiteral();
|
||||
if (obj_proxy != NULL &&
|
||||
key_literal != NULL &&
|
||||
obj_proxy->IsArguments() &&
|
||||
key_literal->handle()->IsSmi()) {
|
||||
// Load arguments object if there are no eval-introduced
|
||||
// variables. Then load the argument from the arguments
|
||||
// object using keyed load.
|
||||
__ lw(a1,
|
||||
ContextSlotOperandCheckExtensions(obj_proxy->var()->rewrite(),
|
||||
slow));
|
||||
__ li(a0, Operand(key_literal->handle()));
|
||||
Handle<Code> ic =
|
||||
isolate()->builtins()->KeyedLoadIC_Initialize();
|
||||
__ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
|
||||
__ Branch(done);
|
||||
}
|
||||
}
|
||||
} else if (var->mode() == Variable::DYNAMIC_LOCAL) {
|
||||
Variable* local = var->local_if_not_shadowed();
|
||||
__ lw(v0, ContextSlotOperandCheckExtensions(local, slow));
|
||||
if (local->mode() == Variable::CONST) {
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
__ subu(at, v0, at); // Sub as compare: at == 0 on eq.
|
||||
__ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
|
||||
__ movz(v0, a0, at); // Conditional move: return Undefined if TheHole.
|
||||
}
|
||||
__ Branch(done);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1241,66 +1223,62 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
||||
SetSourcePosition(proxy->position());
|
||||
Variable* var = proxy->var();
|
||||
|
||||
// Three cases: non-this global variables, lookup slots, and all other
|
||||
// types of slots.
|
||||
Slot* slot = var->rewrite();
|
||||
ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
|
||||
// Three cases: global variables, lookup variables, and all other types of
|
||||
// variables.
|
||||
switch (var->location()) {
|
||||
case Variable::UNALLOCATED: {
|
||||
Comment cmnt(masm_, "Global variable");
|
||||
// Use inline caching. Variable name is passed in a2 and the global
|
||||
// object (receiver) in a0.
|
||||
__ lw(a0, GlobalObjectOperand());
|
||||
__ li(a2, Operand(var->name()));
|
||||
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
|
||||
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||
context()->Plug(v0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (slot == NULL) {
|
||||
Comment cmnt(masm_, "Global variable");
|
||||
// Use inline caching. Variable name is passed in a2 and the global
|
||||
// object (receiver) in a0.
|
||||
__ lw(a0, GlobalObjectOperand());
|
||||
__ li(a2, Operand(var->name()));
|
||||
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
|
||||
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||
context()->Plug(v0);
|
||||
case Variable::PARAMETER:
|
||||
case Variable::LOCAL:
|
||||
case Variable::CONTEXT: {
|
||||
Comment cmnt(masm_, var->IsContextSlot()
|
||||
? "Context variable"
|
||||
: "Stack variable");
|
||||
if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
|
||||
context()->Plug(var);
|
||||
} else {
|
||||
// Let and const need a read barrier.
|
||||
GetVar(v0, var);
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
__ subu(at, v0, at); // Sub as compare: at == 0 on eq.
|
||||
if (var->mode() == Variable::LET) {
|
||||
Label done;
|
||||
__ Branch(&done, ne, at, Operand(zero_reg));
|
||||
__ li(a0, Operand(var->name()));
|
||||
__ push(a0);
|
||||
__ CallRuntime(Runtime::kThrowReferenceError, 1);
|
||||
__ bind(&done);
|
||||
} else {
|
||||
__ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
|
||||
__ movz(v0, a0, at); // Conditional move: Undefined if TheHole.
|
||||
}
|
||||
context()->Plug(v0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (slot->type() == Slot::LOOKUP) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
Comment cmnt(masm_, "Lookup slot");
|
||||
__ li(a1, Operand(var->name()));
|
||||
__ Push(cp, a1); // Context and name.
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ bind(&done);
|
||||
|
||||
context()->Plug(v0);
|
||||
|
||||
} else {
|
||||
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
|
||||
? "Context slot"
|
||||
: "Stack slot");
|
||||
if (var->mode() == Variable::CONST) {
|
||||
// Constants may be the hole value if they have not been initialized.
|
||||
// Unhole them.
|
||||
MemOperand slot_operand = EmitSlotSearch(slot, a0);
|
||||
__ lw(v0, slot_operand);
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
__ subu(at, v0, at); // Sub as compare: at == 0 on eq.
|
||||
__ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
|
||||
__ movz(v0, a0, at); // Conditional move.
|
||||
context()->Plug(v0);
|
||||
} else if (var->mode() == Variable::LET) {
|
||||
// Let bindings may be the hole value if they have not been initialized.
|
||||
// Throw a type error in this case.
|
||||
Label done;
|
||||
MemOperand slot_operand = EmitSlotSearch(slot, a0);
|
||||
__ lw(v0, slot_operand);
|
||||
__ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
|
||||
__ Branch(&done, ne, v0, Operand(a1));
|
||||
__ li(v0, Operand(var->name()));
|
||||
__ push(v0);
|
||||
__ CallRuntime(Runtime::kThrowReferenceError, 1);
|
||||
case Variable::LOOKUP: {
|
||||
Label done, slow;
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
|
||||
__ bind(&slow);
|
||||
Comment cmnt(masm_, "Lookup variable");
|
||||
__ li(a1, Operand(var->name()));
|
||||
__ Push(cp, a1); // Context and name.
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ bind(&done);
|
||||
context()->Plug(v0);
|
||||
} else {
|
||||
context()->Plug(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1839,14 +1817,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
|
||||
|
||||
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
||||
Token::Value op) {
|
||||
ASSERT(var != NULL);
|
||||
ASSERT(var->is_global() || var->rewrite() != NULL);
|
||||
|
||||
if (var->is_global()) {
|
||||
ASSERT(!var->is_this());
|
||||
// Assignment to a global variable. Use inline caching for the
|
||||
// assignment. Right-hand-side value is passed in a0, variable name in
|
||||
// a2, and the global object in a1.
|
||||
if (var->IsUnallocated()) {
|
||||
// Global var, const, or let.
|
||||
__ mov(a0, result_register());
|
||||
__ li(a2, Operand(var->name()));
|
||||
__ lw(a1, GlobalObjectOperand());
|
||||
@@ -1856,121 +1828,83 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
||||
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||
|
||||
} else if (op == Token::INIT_CONST) {
|
||||
// Like var declarations, const declarations are hoisted to function
|
||||
// scope. However, unlike var initializers, const initializers are able
|
||||
// to drill a hole to that function context, even from inside a 'with'
|
||||
// context. We thus bypass the normal static scope lookup.
|
||||
Slot* slot = var->rewrite();
|
||||
Label skip;
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
// No const parameters.
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case Slot::LOCAL:
|
||||
// Detect const reinitialization by checking for the hole value.
|
||||
__ lw(a1, MemOperand(fp, SlotOffset(slot)));
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ Branch(&skip, ne, a1, Operand(t0));
|
||||
__ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
break;
|
||||
case Slot::CONTEXT:
|
||||
case Slot::LOOKUP:
|
||||
__ push(result_register());
|
||||
__ li(a0, Operand(slot->var()->name()));
|
||||
__ Push(cp, a0); // Context and name.
|
||||
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
||||
break;
|
||||
case Slot::GLOBAL:
|
||||
UNREACHABLE();
|
||||
// Const initializers need a write barrier.
|
||||
ASSERT(!var->IsParameter()); // No const parameters.
|
||||
if (var->IsStackLocal()) {
|
||||
Label skip;
|
||||
__ lw(a1, StackOperand(var));
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ Branch(&skip, ne, a1, Operand(t0));
|
||||
__ sw(result_register(), StackOperand(var));
|
||||
__ bind(&skip);
|
||||
} else {
|
||||
ASSERT(var->IsContextSlot() || var->IsLookupSlot());
|
||||
// Like var declarations, const declarations are hoisted to function
|
||||
// scope. However, unlike var initializers, const initializers are
|
||||
// able to drill a hole to that function context, even from inside a
|
||||
// 'with' context. We thus bypass the normal static scope lookup for
|
||||
// var->IsContextSlot().
|
||||
__ push(v0);
|
||||
__ li(a0, Operand(var->name()));
|
||||
__ Push(cp, a0); // Context and name.
|
||||
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
||||
}
|
||||
__ bind(&skip);
|
||||
|
||||
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
|
||||
// Perform the assignment for non-const variables. Const assignments
|
||||
// are simply skipped.
|
||||
Slot* slot = var->AsSlot();
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL: {
|
||||
Label assign;
|
||||
// Check for an initialized let binding.
|
||||
__ lw(a1, MemOperand(fp, SlotOffset(slot)));
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ Branch(&assign, ne, a1, Operand(t0));
|
||||
__ li(a1, Operand(var->name()));
|
||||
__ push(a1);
|
||||
__ CallRuntime(Runtime::kThrowReferenceError, 1);
|
||||
// Perform the assignment.
|
||||
__ bind(&assign);
|
||||
__ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
break;
|
||||
}
|
||||
case Slot::CONTEXT: {
|
||||
// Let variables may be the hole value if they have not been
|
||||
// initialized. Throw a type error in this case.
|
||||
Label assign;
|
||||
MemOperand target = EmitSlotSearch(slot, a1);
|
||||
// Check for an initialized let binding.
|
||||
__ lw(a3, target);
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ Branch(&assign, ne, a3, Operand(t0));
|
||||
__ li(a3, Operand(var->name()));
|
||||
__ push(a3);
|
||||
__ CallRuntime(Runtime::kThrowReferenceError, 1);
|
||||
// Perform the assignment.
|
||||
__ bind(&assign);
|
||||
__ sw(result_register(), target);
|
||||
// Non-initializing assignment to let variable needs a write barrier.
|
||||
if (var->IsLookupSlot()) {
|
||||
__ push(v0); // Value.
|
||||
__ li(a1, Operand(var->name()));
|
||||
__ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ Push(cp, a1, a0); // Context, name, strict mode.
|
||||
__ CallRuntime(Runtime::kStoreContextSlot, 4);
|
||||
} else {
|
||||
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
|
||||
Label assign;
|
||||
MemOperand location = VarOperand(var, a1);
|
||||
__ lw(a3, location);
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ Branch(&assign, ne, a3, Operand(t0));
|
||||
__ li(a3, Operand(var->name()));
|
||||
__ push(a3);
|
||||
__ CallRuntime(Runtime::kThrowReferenceError, 1);
|
||||
// Perform the assignment.
|
||||
__ bind(&assign);
|
||||
__ sw(result_register(), location);
|
||||
if (var->IsContextSlot()) {
|
||||
// RecordWrite may destroy all its register arguments.
|
||||
__ mov(a3, result_register());
|
||||
int offset = Context::SlotOffset(slot->index());
|
||||
int offset = Context::SlotOffset(var->index());
|
||||
__ RecordWrite(a1, Operand(offset), a2, a3);
|
||||
break;
|
||||
}
|
||||
case Slot::LOOKUP:
|
||||
// Call the runtime for the assignment.
|
||||
__ push(v0); // Value.
|
||||
__ li(a1, Operand(slot->var()->name()));
|
||||
__ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ Push(cp, a1, a0); // Context, name, strict mode.
|
||||
__ CallRuntime(Runtime::kStoreContextSlot, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (var->mode() != Variable::CONST) {
|
||||
// Perform the assignment for non-const variables. Const assignments
|
||||
// are simply skipped.
|
||||
Slot* slot = var->rewrite();
|
||||
switch (slot->type()) {
|
||||
case Slot::PARAMETER:
|
||||
case Slot::LOCAL:
|
||||
// Perform the assignment.
|
||||
__ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
|
||||
break;
|
||||
|
||||
case Slot::CONTEXT: {
|
||||
MemOperand target = EmitSlotSearch(slot, a1);
|
||||
// Perform the assignment and issue the write barrier.
|
||||
__ sw(result_register(), target);
|
||||
// RecordWrite may destroy all its register arguments.
|
||||
__ mov(a3, result_register());
|
||||
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
||||
__ RecordWrite(a1, Operand(offset), a2, a3);
|
||||
break;
|
||||
// Assignment to var or initializing assignment to let.
|
||||
if (var->IsStackAllocated() || var->IsContextSlot()) {
|
||||
MemOperand location = VarOperand(var, a1);
|
||||
if (FLAG_debug_code && op == Token::INIT_LET) {
|
||||
// Check for an uninitialized let binding.
|
||||
__ lw(a2, location);
|
||||
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
|
||||
__ Check(eq, "Let binding re-initialization.", a2, Operand(t0));
|
||||
}
|
||||
|
||||
case Slot::LOOKUP:
|
||||
// Call the runtime for the assignment.
|
||||
__ push(v0); // Value.
|
||||
__ li(a1, Operand(slot->var()->name()));
|
||||
__ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ Push(cp, a1, a0); // Context, name, strict mode.
|
||||
__ CallRuntime(Runtime::kStoreContextSlot, 4);
|
||||
break;
|
||||
|
||||
case Slot::GLOBAL:
|
||||
UNREACHABLE();
|
||||
// Perform the assignment.
|
||||
__ sw(v0, location);
|
||||
if (var->IsContextSlot()) {
|
||||
__ mov(a3, v0);
|
||||
__ RecordWrite(a1, Operand(Context::SlotOffset(var->index())), a2, a3);
|
||||
}
|
||||
} else {
|
||||
ASSERT(var->IsLookupSlot());
|
||||
__ push(v0); // Value.
|
||||
__ li(a1, Operand(var->name()));
|
||||
__ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ Push(cp, a1, a0); // Context, name, strict mode.
|
||||
__ CallRuntime(Runtime::kStoreContextSlot, 4);
|
||||
}
|
||||
}
|
||||
// Non-initializing assignments to consts are ignored.
|
||||
}
|
||||
|
||||
|
||||
@@ -2211,10 +2145,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
#endif
|
||||
|
||||
Comment cmnt(masm_, "[ Call");
|
||||
Expression* fun = expr->expression();
|
||||
Variable* var = fun->AsVariableProxy()->AsVariable();
|
||||
Expression* callee = expr->expression();
|
||||
VariableProxy* proxy = callee->AsVariableProxy();
|
||||
Property* property = callee->AsProperty();
|
||||
|
||||
if (var != NULL && var->is_possibly_eval()) {
|
||||
if (proxy != NULL && proxy->var()->is_possibly_eval()) {
|
||||
// In a call to eval, we first call %ResolvePossiblyDirectEval to
|
||||
// resolve the function we need to call and the receiver of the
|
||||
// call. Then we call the resolved function using the given
|
||||
@@ -2223,7 +2158,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
int arg_count = args->length();
|
||||
|
||||
{ PreservePositionScope pos_scope(masm()->positions_recorder());
|
||||
VisitForStackValue(fun);
|
||||
VisitForStackValue(callee);
|
||||
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
|
||||
__ push(a2); // Reserved receiver slot.
|
||||
|
||||
@@ -2231,16 +2166,16 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
|
||||
// If we know that eval can only be shadowed by eval-introduced
|
||||
// variables we attempt to load the global eval function directly
|
||||
// in generated code. If we succeed, there is no need to perform a
|
||||
// context lookup in the runtime system.
|
||||
Label done;
|
||||
if (var->rewrite() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
Variable* var = proxy->var();
|
||||
if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
|
||||
Label slow;
|
||||
EmitLoadGlobalSlotCheckExtensions(var->rewrite(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow);
|
||||
EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
|
||||
// Push the function and resolve eval.
|
||||
__ push(v0);
|
||||
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
|
||||
@@ -2248,14 +2183,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
__ bind(&slow);
|
||||
}
|
||||
|
||||
// Push copy of the function (found below the arguments) and
|
||||
// Push a copy of the function (found below the arguments) and
|
||||
// resolve eval.
|
||||
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ push(a1);
|
||||
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
|
||||
if (done.is_linked()) {
|
||||
__ bind(&done);
|
||||
}
|
||||
__ bind(&done);
|
||||
|
||||
// The runtime call returns a pair of values in v0 (function) and
|
||||
// v1 (receiver). Touch up the stack with the right values.
|
||||
@@ -2271,30 +2204,26 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// Restore context register.
|
||||
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||
context()->DropAndPlug(1, v0);
|
||||
} else if (var != NULL && !var->is_this() && var->is_global()) {
|
||||
} else if (proxy != NULL && proxy->var()->IsUnallocated()) {
|
||||
// Push global object as receiver for the call IC.
|
||||
__ lw(a0, GlobalObjectOperand());
|
||||
__ push(a0);
|
||||
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
|
||||
} else if (var != NULL && var->rewrite() != NULL &&
|
||||
var->rewrite()->type() == Slot::LOOKUP) {
|
||||
EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
|
||||
} else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
|
||||
// Call to a lookup slot (dynamically introduced variable).
|
||||
Label slow, done;
|
||||
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->rewrite(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow,
|
||||
&done);
|
||||
EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
|
||||
}
|
||||
|
||||
__ bind(&slow);
|
||||
// Call the runtime to find the function to call (returned in v0)
|
||||
// and the object holding it (returned in v1).
|
||||
__ push(context_register());
|
||||
__ li(a2, Operand(var->name()));
|
||||
__ li(a2, Operand(proxy->name()));
|
||||
__ push(a2);
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ Push(v0, v1); // Function, receiver.
|
||||
@@ -2319,26 +2248,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// by LoadContextSlot. That object could be the hole if the
|
||||
// receiver is implicitly the global object.
|
||||
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
|
||||
} else if (fun->AsProperty() != NULL) {
|
||||
// Call to an object property.
|
||||
Property* prop = fun->AsProperty();
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
if (key != NULL && key->handle()->IsSymbol()) {
|
||||
// Call to a named property, use call IC.
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||
} else if (property != NULL) {
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(property->obj());
|
||||
}
|
||||
if (property->key()->IsPropertyName()) {
|
||||
EmitCallWithIC(expr,
|
||||
property->key()->AsLiteral()->handle(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Call to a keyed property.
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitKeyedCallWithIC(expr, prop->key());
|
||||
EmitKeyedCallWithIC(expr, property->key());
|
||||
}
|
||||
} else {
|
||||
// Call to an arbitrary expression not handled specially above.
|
||||
{ PreservePositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(fun);
|
||||
VisitForStackValue(callee);
|
||||
}
|
||||
// Load global receiver object.
|
||||
__ lw(a1, GlobalObjectOperand());
|
||||
@@ -3668,32 +3592,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
switch (expr->op()) {
|
||||
case Token::DELETE: {
|
||||
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
|
||||
Property* prop = expr->expression()->AsProperty();
|
||||
Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
|
||||
Property* property = expr->expression()->AsProperty();
|
||||
VariableProxy* proxy = expr->expression()->AsVariableProxy();
|
||||
|
||||
if (prop != NULL) {
|
||||
VisitForStackValue(prop->obj());
|
||||
VisitForStackValue(prop->key());
|
||||
if (property != NULL) {
|
||||
VisitForStackValue(property->obj());
|
||||
VisitForStackValue(property->key());
|
||||
__ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
|
||||
__ push(a1);
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(v0);
|
||||
} else if (var != NULL) {
|
||||
} else if (proxy != NULL) {
|
||||
Variable* var = proxy->var();
|
||||
// Delete of an unqualified identifier is disallowed in strict mode
|
||||
// but "delete this" is.
|
||||
// but "delete this" is allowed.
|
||||
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
|
||||
if (var->is_global()) {
|
||||
if (var->IsUnallocated()) {
|
||||
__ lw(a2, GlobalObjectOperand());
|
||||
__ li(a1, Operand(var->name()));
|
||||
__ li(a0, Operand(Smi::FromInt(kNonStrictMode)));
|
||||
__ Push(a2, a1, a0);
|
||||
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
||||
context()->Plug(v0);
|
||||
} else if (var->rewrite() != NULL &&
|
||||
var->rewrite()->type() != Slot::LOOKUP) {
|
||||
} else if (var->IsStackAllocated() || var->IsContextSlot()) {
|
||||
// Result of deleting non-global, non-dynamic variables is false.
|
||||
// The subexpression does not have side effects.
|
||||
context()->Plug(false);
|
||||
context()->Plug(var->is_this());
|
||||
} else {
|
||||
// Non-global variable. Call the runtime to try to delete from the
|
||||
// context where the variable was introduced.
|
||||
@@ -3968,8 +3892,10 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
|
||||
void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
|
||||
ASSERT(!context()->IsEffect());
|
||||
ASSERT(!context()->IsTest());
|
||||
VariableProxy* proxy = expr->AsVariableProxy();
|
||||
if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
|
||||
if (proxy != NULL && proxy->var()->IsUnallocated()) {
|
||||
Comment cmnt(masm_, "Global variable");
|
||||
__ lw(a0, GlobalObjectOperand());
|
||||
__ li(a2, Operand(proxy->name()));
|
||||
@@ -3979,15 +3905,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
|
||||
__ Call(ic);
|
||||
PrepareForBailout(expr, TOS_REG);
|
||||
context()->Plug(v0);
|
||||
} else if (proxy != NULL &&
|
||||
proxy->var()->rewrite() != NULL &&
|
||||
proxy->var()->rewrite()->type() == Slot::LOOKUP) {
|
||||
} else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
|
||||
Label done, slow;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
Slot* slot = proxy->var()->rewrite();
|
||||
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
|
||||
EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
|
||||
|
||||
__ bind(&slow);
|
||||
__ li(a0, Operand(proxy->name()));
|
||||
|
||||
6
deps/v8/src/objects-debug.cc
vendored
6
deps/v8/src/objects-debug.cc
vendored
@@ -257,9 +257,9 @@ void JSObject::JSObjectVerify() {
|
||||
(map()->inobject_properties() + properties()->length() -
|
||||
map()->NextFreePropertyIndex()));
|
||||
}
|
||||
ASSERT(map()->has_fast_elements() ==
|
||||
(elements()->map() == GetHeap()->fixed_array_map() ||
|
||||
elements()->map() == GetHeap()->fixed_cow_array_map()));
|
||||
ASSERT_EQ(map()->has_fast_elements(),
|
||||
(elements()->map() == GetHeap()->fixed_array_map() ||
|
||||
elements()->map() == GetHeap()->fixed_cow_array_map()));
|
||||
ASSERT(map()->has_fast_elements() == HasFastElements());
|
||||
}
|
||||
|
||||
|
||||
1
deps/v8/src/objects.cc
vendored
1
deps/v8/src/objects.cc
vendored
@@ -41,7 +41,6 @@
|
||||
#include "objects-visiting.h"
|
||||
#include "macro-assembler.h"
|
||||
#include "safepoint-table.h"
|
||||
#include "scanner-base.h"
|
||||
#include "string-stream.h"
|
||||
#include "utils.h"
|
||||
#include "vm-state-inl.h"
|
||||
|
||||
8
deps/v8/src/parser.cc
vendored
8
deps/v8/src/parser.cc
vendored
@@ -39,6 +39,7 @@
|
||||
#include "platform.h"
|
||||
#include "preparser.h"
|
||||
#include "runtime.h"
|
||||
#include "scanner-character-streams.h"
|
||||
#include "scopeinfo.h"
|
||||
#include "string-stream.h"
|
||||
|
||||
@@ -2216,8 +2217,6 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
|
||||
if (peek() == Token::LBRACE) {
|
||||
// Rewrite the catch body { B } to a block:
|
||||
// { { B } ExitContext; }.
|
||||
Target target(&this->target_stack_, &catch_collector);
|
||||
catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
|
||||
if (top_scope_->is_strict_mode()) {
|
||||
@@ -2226,14 +2225,11 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
Variable::Mode mode = harmony_block_scoping_
|
||||
? Variable::LET : Variable::VAR;
|
||||
catch_variable = catch_scope->DeclareLocal(name, mode);
|
||||
catch_block = new(zone()) Block(isolate(), NULL, 2, false);
|
||||
|
||||
Scope* saved_scope = top_scope_;
|
||||
top_scope_ = catch_scope;
|
||||
Block* catch_body = ParseBlock(NULL, CHECK_OK);
|
||||
catch_block = ParseBlock(NULL, CHECK_OK);
|
||||
top_scope_ = saved_scope;
|
||||
catch_block->AddStatement(catch_body);
|
||||
catch_block->AddStatement(new(zone()) ExitContextStatement());
|
||||
} else {
|
||||
Expect(Token::LBRACE, CHECK_OK);
|
||||
}
|
||||
|
||||
3
deps/v8/src/parser.h
vendored
3
deps/v8/src/parser.h
vendored
@@ -30,10 +30,9 @@
|
||||
|
||||
#include "allocation.h"
|
||||
#include "ast.h"
|
||||
#include "scanner.h"
|
||||
#include "scopes.h"
|
||||
#include "preparse-data-format.h"
|
||||
#include "preparse-data.h"
|
||||
#include "scopes.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
70
deps/v8/src/platform-win32.cc
vendored
70
deps/v8/src/platform-win32.cc
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright 2006-2008 the V8 project authors. All rights reserved.
|
||||
// Copyright 2011 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:
|
||||
@@ -35,76 +35,8 @@
|
||||
#include "platform.h"
|
||||
#include "vm-state-inl.h"
|
||||
|
||||
// Extra POSIX/ANSI routines for Win32 when when using Visual Studio C++. Please
|
||||
// refer to The Open Group Base Specification for specification of the correct
|
||||
// semantics for these functions.
|
||||
// (http://www.opengroup.org/onlinepubs/000095399/)
|
||||
#ifdef _MSC_VER
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Test for finite value - usually defined in math.h
|
||||
int isfinite(double x) {
|
||||
return _finite(x);
|
||||
}
|
||||
|
||||
} // namespace v8
|
||||
} // namespace internal
|
||||
|
||||
// Test for a NaN (not a number) value - usually defined in math.h
|
||||
int isnan(double x) {
|
||||
return _isnan(x);
|
||||
}
|
||||
|
||||
|
||||
// Test for infinity - usually defined in math.h
|
||||
int isinf(double x) {
|
||||
return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0;
|
||||
}
|
||||
|
||||
|
||||
// Test if x is less than y and both nominal - usually defined in math.h
|
||||
int isless(double x, double y) {
|
||||
return isnan(x) || isnan(y) ? 0 : x < y;
|
||||
}
|
||||
|
||||
|
||||
// Test if x is greater than y and both nominal - usually defined in math.h
|
||||
int isgreater(double x, double y) {
|
||||
return isnan(x) || isnan(y) ? 0 : x > y;
|
||||
}
|
||||
|
||||
|
||||
// Classify floating point number - usually defined in math.h
|
||||
int fpclassify(double x) {
|
||||
// Use the MS-specific _fpclass() for classification.
|
||||
int flags = _fpclass(x);
|
||||
|
||||
// Determine class. We cannot use a switch statement because
|
||||
// the _FPCLASS_ constants are defined as flags.
|
||||
if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL;
|
||||
if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO;
|
||||
if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL;
|
||||
if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE;
|
||||
|
||||
// All cases should be covered by the code above.
|
||||
ASSERT(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN));
|
||||
return FP_NAN;
|
||||
}
|
||||
|
||||
|
||||
// Test sign - usually defined in math.h
|
||||
int signbit(double x) {
|
||||
// We need to take care of the special case of both positive
|
||||
// and negative versions of zero.
|
||||
if (x == 0)
|
||||
return _fpclass(x) & _FPCLASS_NZ;
|
||||
else
|
||||
return x < 0;
|
||||
}
|
||||
|
||||
|
||||
// Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually
|
||||
// defined in strings.h.
|
||||
int strncasecmp(const char* s1, const char* s2, int n) {
|
||||
|
||||
71
deps/v8/src/platform.h
vendored
71
deps/v8/src/platform.h
vendored
@@ -44,53 +44,12 @@
|
||||
#ifndef V8_PLATFORM_H_
|
||||
#define V8_PLATFORM_H_
|
||||
|
||||
#define V8_INFINITY INFINITY
|
||||
|
||||
// Windows specific stuff.
|
||||
#ifdef WIN32
|
||||
|
||||
// Microsoft Visual C++ specific stuff.
|
||||
#ifdef _MSC_VER
|
||||
|
||||
enum {
|
||||
FP_NAN,
|
||||
FP_INFINITE,
|
||||
FP_ZERO,
|
||||
FP_SUBNORMAL,
|
||||
FP_NORMAL
|
||||
};
|
||||
|
||||
#undef V8_INFINITY
|
||||
#define V8_INFINITY HUGE_VAL
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
int isfinite(double x);
|
||||
} }
|
||||
int isnan(double x);
|
||||
int isinf(double x);
|
||||
int isless(double x, double y);
|
||||
int isgreater(double x, double y);
|
||||
int fpclassify(double x);
|
||||
int signbit(double x);
|
||||
|
||||
int strncasecmp(const char* s1, const char* s2, int n);
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Random is missing on both Visual Studio and MinGW.
|
||||
int random();
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
|
||||
#ifdef __sun
|
||||
# ifndef signbit
|
||||
int signbit(double x);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// GCC specific stuff
|
||||
#ifdef __GNUC__
|
||||
|
||||
@@ -99,20 +58,26 @@ int signbit(double x);
|
||||
|
||||
#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
|
||||
|
||||
// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
|
||||
// warning flag and certain versions of GCC due to a bug:
|
||||
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
|
||||
// For now, we use the more involved template-based version from <limits>, but
|
||||
// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
|
||||
// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
|
||||
#if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100
|
||||
#include <limits>
|
||||
#undef V8_INFINITY
|
||||
#define V8_INFINITY std::numeric_limits<double>::infinity()
|
||||
#endif
|
||||
|
||||
#endif // __GNUC__
|
||||
|
||||
|
||||
// Windows specific stuff.
|
||||
#ifdef WIN32
|
||||
|
||||
// Microsoft Visual C++ specific stuff.
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include "win32-math.h"
|
||||
|
||||
int strncasecmp(const char* s1, const char* s2, int n);
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Random is missing on both Visual Studio and MinGW.
|
||||
int random();
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
#include "atomicops.h"
|
||||
#include "platform-tls.h"
|
||||
#include "utils.h"
|
||||
|
||||
8
deps/v8/src/preparser-api.cc
vendored
8
deps/v8/src/preparser-api.cc
vendored
@@ -25,15 +25,19 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define V8_WIN32_LEAN_AND_MEAN
|
||||
#include "win32-headers.h"
|
||||
#endif
|
||||
|
||||
#include "../include/v8-preparser.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "checks.h"
|
||||
#include "allocation.h"
|
||||
#include "utils.h"
|
||||
#include "list.h"
|
||||
#include "scanner-base.h"
|
||||
#include "hashmap.h"
|
||||
#include "preparse-data-format.h"
|
||||
#include "preparse-data.h"
|
||||
#include "preparser.h"
|
||||
|
||||
274
deps/v8/src/preparser.cc
vendored
274
deps/v8/src/preparser.cc
vendored
@@ -25,22 +25,31 @@
|
||||
// (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 "../include/v8stdint.h"
|
||||
#include "unicode.h"
|
||||
#include "globals.h"
|
||||
#include "checks.h"
|
||||
#include "allocation.h"
|
||||
#include "utils.h"
|
||||
#include "list.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "scanner-base.h"
|
||||
#include "../include/v8stdint.h"
|
||||
|
||||
#include "allocation.h"
|
||||
#include "checks.h"
|
||||
#include "conversions.h"
|
||||
#include "conversions-inl.h"
|
||||
#include "globals.h"
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
#include "preparse-data-format.h"
|
||||
#include "preparse-data.h"
|
||||
#include "preparser.h"
|
||||
|
||||
#include "conversions-inl.h"
|
||||
#include "unicode.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Usually defined in math.h, but not in MSVC.
|
||||
// Abstracted to work
|
||||
int isfinite(double value);
|
||||
#endif
|
||||
|
||||
namespace preparser {
|
||||
|
||||
// Preparsing checks a JavaScript program and emits preparse-data that helps
|
||||
@@ -68,27 +77,22 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
|
||||
// Four of the tokens are treated specially
|
||||
switch (token) {
|
||||
case i::Token::EOS:
|
||||
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
|
||||
"unexpected_eos", NULL);
|
||||
return ReportMessageAt(source_location, "unexpected_eos", NULL);
|
||||
case i::Token::NUMBER:
|
||||
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
|
||||
"unexpected_token_number", NULL);
|
||||
return ReportMessageAt(source_location, "unexpected_token_number", NULL);
|
||||
case i::Token::STRING:
|
||||
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
|
||||
"unexpected_token_string", NULL);
|
||||
return ReportMessageAt(source_location, "unexpected_token_string", NULL);
|
||||
case i::Token::IDENTIFIER:
|
||||
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
|
||||
return ReportMessageAt(source_location,
|
||||
"unexpected_token_identifier", NULL);
|
||||
case i::Token::FUTURE_RESERVED_WORD:
|
||||
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
|
||||
"unexpected_reserved", NULL);
|
||||
return ReportMessageAt(source_location, "unexpected_reserved", NULL);
|
||||
case i::Token::FUTURE_STRICT_RESERVED_WORD:
|
||||
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
|
||||
return ReportMessageAt(source_location,
|
||||
"unexpected_strict_reserved", NULL);
|
||||
default:
|
||||
const char* name = i::Token::String(token);
|
||||
ReportMessageAt(source_location.beg_pos, source_location.end_pos,
|
||||
"unexpected_token", name);
|
||||
ReportMessageAt(source_location, "unexpected_token", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +102,7 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
|
||||
void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
||||
i::Scanner::Location octal = scanner_->octal_position();
|
||||
if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
|
||||
ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL);
|
||||
ReportMessageAt(octal, "strict_octal_literal", NULL);
|
||||
scanner_->clear_octal_position();
|
||||
*ok = false;
|
||||
}
|
||||
@@ -251,7 +255,7 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
|
||||
if (identifier.IsFutureStrictReserved()) {
|
||||
type = "strict_reserved_word";
|
||||
}
|
||||
ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
|
||||
ReportMessageAt(location, type, NULL);
|
||||
*ok = false;
|
||||
}
|
||||
return Statement::FunctionDeclaration();
|
||||
@@ -313,8 +317,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
||||
} else if (peek() == i::Token::CONST) {
|
||||
if (strict_mode()) {
|
||||
i::Scanner::Location location = scanner_->peek_location();
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
"strict_const", NULL);
|
||||
ReportMessageAt(location, "strict_const", NULL);
|
||||
*ok = false;
|
||||
return Statement::Default();
|
||||
}
|
||||
@@ -475,8 +478,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
|
||||
Expect(i::Token::WITH, CHECK_OK);
|
||||
if (strict_mode()) {
|
||||
i::Scanner::Location location = scanner_->location();
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
"strict_mode_with", NULL);
|
||||
ReportMessageAt(location, "strict_mode_with", NULL);
|
||||
*ok = false;
|
||||
return Statement::Default();
|
||||
}
|
||||
@@ -612,8 +614,7 @@ PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
|
||||
Expect(i::Token::THROW, CHECK_OK);
|
||||
if (scanner_->HasAnyLineTerminatorBeforeNext()) {
|
||||
i::JavaScriptScanner::Location pos = scanner_->location();
|
||||
ReportMessageAt(pos.beg_pos, pos.end_pos,
|
||||
"newline_after_throw", NULL);
|
||||
ReportMessageAt(pos, "newline_after_throw", NULL);
|
||||
*ok = false;
|
||||
return Statement::Default();
|
||||
}
|
||||
@@ -1025,8 +1026,7 @@ PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
|
||||
if (strict_mode()) {
|
||||
Next();
|
||||
i::Scanner::Location location = scanner_->location();
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
"strict_reserved_word", NULL);
|
||||
ReportMessageAt(location, "strict_reserved_word", NULL);
|
||||
*ok = false;
|
||||
return Expression::Default();
|
||||
}
|
||||
@@ -1107,6 +1107,39 @@ PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
|
||||
return Expression::Default();
|
||||
}
|
||||
|
||||
void PreParser::CheckDuplicate(DuplicateFinder* finder,
|
||||
i::Token::Value property,
|
||||
int type,
|
||||
bool* ok) {
|
||||
int old_type;
|
||||
if (property == i::Token::NUMBER) {
|
||||
old_type = finder->AddNumber(scanner_->literal_ascii_string(), type);
|
||||
} else if (scanner_->is_literal_ascii()) {
|
||||
old_type = finder->AddAsciiSymbol(scanner_->literal_ascii_string(),
|
||||
type);
|
||||
} else {
|
||||
old_type = finder->AddUC16Symbol(scanner_->literal_uc16_string(), type);
|
||||
}
|
||||
if (HasConflict(old_type, type)) {
|
||||
if (IsDataDataConflict(old_type, type)) {
|
||||
// Both are data properties.
|
||||
if (!strict_mode()) return;
|
||||
ReportMessageAt(scanner_->location(),
|
||||
"strict_duplicate_property", NULL);
|
||||
} else if (IsDataAccessorConflict(old_type, type)) {
|
||||
// Both a data and an accessor property with the same name.
|
||||
ReportMessageAt(scanner_->location(),
|
||||
"accessor_data_property", NULL);
|
||||
} else {
|
||||
ASSERT(IsAccessorAccessorConflict(old_type, type));
|
||||
// Both accessors of the same type.
|
||||
ReportMessageAt(scanner_->location(),
|
||||
"accessor_get_set", NULL);
|
||||
}
|
||||
*ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
||||
// ObjectLiteral ::
|
||||
@@ -1116,6 +1149,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
||||
// )*[','] '}'
|
||||
|
||||
Expect(i::Token::LBRACE, CHECK_OK);
|
||||
DuplicateFinder duplicate_finder(scanner_->unicode_cache());
|
||||
while (peek() != i::Token::RBRACE) {
|
||||
i::Token::Value next = peek();
|
||||
switch (next) {
|
||||
@@ -1140,24 +1174,30 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
||||
if (!is_keyword) {
|
||||
LogSymbol();
|
||||
}
|
||||
PropertyType type = is_getter ? kGetterProperty : kSetterProperty;
|
||||
CheckDuplicate(&duplicate_finder, name, type, CHECK_OK);
|
||||
ParseFunctionLiteral(CHECK_OK);
|
||||
if (peek() != i::Token::RBRACE) {
|
||||
Expect(i::Token::COMMA, CHECK_OK);
|
||||
}
|
||||
continue; // restart the while
|
||||
}
|
||||
CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
|
||||
break;
|
||||
}
|
||||
case i::Token::STRING:
|
||||
Consume(next);
|
||||
CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
|
||||
GetStringSymbol();
|
||||
break;
|
||||
case i::Token::NUMBER:
|
||||
Consume(next);
|
||||
CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
|
||||
break;
|
||||
default:
|
||||
if (i::Token::IsKeyword(next)) {
|
||||
Consume(next);
|
||||
CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
|
||||
} else {
|
||||
// Unexpected token.
|
||||
*ok = false;
|
||||
@@ -1182,9 +1222,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
|
||||
bool* ok) {
|
||||
if (!scanner_->ScanRegExpPattern(seen_equal)) {
|
||||
Next();
|
||||
i::JavaScriptScanner::Location location = scanner_->location();
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
"unterminated_regexp", NULL);
|
||||
ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL);
|
||||
*ok = false;
|
||||
return Expression::Default();
|
||||
}
|
||||
@@ -1193,9 +1231,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
|
||||
|
||||
if (!scanner_->ScanRegExpFlags()) {
|
||||
Next();
|
||||
i::JavaScriptScanner::Location location = scanner_->location();
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
"invalid_regexp_flags", NULL);
|
||||
ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL);
|
||||
*ok = false;
|
||||
return Expression::Default();
|
||||
}
|
||||
@@ -1240,6 +1276,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
|
||||
Expect(i::Token::LPAREN, CHECK_OK);
|
||||
int start_position = scanner_->location().beg_pos;
|
||||
bool done = (peek() == i::Token::RPAREN);
|
||||
DuplicateFinder duplicate_finder(scanner_->unicode_cache());
|
||||
while (!done) {
|
||||
Identifier id = ParseIdentifier(CHECK_OK);
|
||||
if (!id.IsValidStrictVariable()) {
|
||||
@@ -1248,6 +1285,20 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
|
||||
id,
|
||||
CHECK_OK);
|
||||
}
|
||||
int prev_value;
|
||||
if (scanner_->is_literal_ascii()) {
|
||||
prev_value =
|
||||
duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1);
|
||||
} else {
|
||||
prev_value =
|
||||
duplicate_finder.AddUC16Symbol(scanner_->literal_uc16_string(), 1);
|
||||
}
|
||||
|
||||
if (prev_value != 0) {
|
||||
SetStrictModeViolation(scanner_->location(),
|
||||
"strict_param_dupe",
|
||||
CHECK_OK);
|
||||
}
|
||||
done = (peek() == i::Token::RPAREN);
|
||||
if (!done) {
|
||||
Expect(i::Token::COMMA, CHECK_OK);
|
||||
@@ -1399,13 +1450,18 @@ void PreParser::SetStrictModeViolation(i::Scanner::Location location,
|
||||
const char* type,
|
||||
bool* ok) {
|
||||
if (strict_mode()) {
|
||||
ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
|
||||
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;
|
||||
}
|
||||
@@ -1417,11 +1473,9 @@ void PreParser::CheckDelayedStrictModeViolation(int beg_pos,
|
||||
i::Scanner::Location location = strict_mode_violation_location_;
|
||||
if (location.IsValid() &&
|
||||
location.beg_pos > beg_pos && location.end_pos < end_pos) {
|
||||
ReportMessageAt(location.beg_pos, location.end_pos,
|
||||
strict_mode_violation_type_, NULL);
|
||||
ReportMessageAt(location, strict_mode_violation_type_, NULL);
|
||||
*ok = false;
|
||||
}
|
||||
strict_mode_violation_location_ = i::Scanner::Location::invalid();
|
||||
}
|
||||
|
||||
|
||||
@@ -1436,7 +1490,7 @@ void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location,
|
||||
type = "strict_reserved_word";
|
||||
}
|
||||
if (strict_mode()) {
|
||||
ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
|
||||
ReportMessageAt(location, type, NULL);
|
||||
*ok = false;
|
||||
return;
|
||||
}
|
||||
@@ -1488,4 +1542,138 @@ bool PreParser::peek_any_identifier() {
|
||||
next == i::Token::FUTURE_RESERVED_WORD ||
|
||||
next == i::Token::FUTURE_STRICT_RESERVED_WORD;
|
||||
}
|
||||
|
||||
|
||||
int DuplicateFinder::AddAsciiSymbol(i::Vector<const char> key, int value) {
|
||||
return AddSymbol(i::Vector<const byte>::cast(key), true, value);
|
||||
}
|
||||
|
||||
int DuplicateFinder::AddUC16Symbol(i::Vector<const uint16_t> key, int value) {
|
||||
return AddSymbol(i::Vector<const byte>::cast(key), false, value);
|
||||
}
|
||||
|
||||
int DuplicateFinder::AddSymbol(i::Vector<const byte> key,
|
||||
bool is_ascii,
|
||||
int value) {
|
||||
uint32_t hash = Hash(key, is_ascii);
|
||||
byte* encoding = BackupKey(key, is_ascii);
|
||||
i::HashMap::Entry* entry = map_.Lookup(encoding, hash, true);
|
||||
int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
|
||||
entry->value =
|
||||
reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
|
||||
int DuplicateFinder::AddNumber(i::Vector<const char> key, int value) {
|
||||
ASSERT(key.length() > 0);
|
||||
// Quick check for already being in canonical form.
|
||||
if (IsNumberCanonical(key)) {
|
||||
return AddAsciiSymbol(key, value);
|
||||
}
|
||||
|
||||
int flags = i::ALLOW_HEX | i::ALLOW_OCTALS;
|
||||
double double_value = StringToDouble(unicode_constants_, key, flags, 0.0);
|
||||
int length;
|
||||
const char* string;
|
||||
if (!isfinite(double_value)) {
|
||||
string = "Infinity";
|
||||
length = 8; // strlen("Infinity");
|
||||
} else {
|
||||
string = DoubleToCString(double_value,
|
||||
i::Vector<char>(number_buffer_, kBufferSize));
|
||||
length = i::StrLength(string);
|
||||
}
|
||||
return AddSymbol(i::Vector<const byte>(reinterpret_cast<const byte*>(string),
|
||||
length), true, value);
|
||||
}
|
||||
|
||||
|
||||
bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) {
|
||||
// Test for a safe approximation of number literals that are already
|
||||
// in canonical form: max 15 digits, no leading zeroes, except an
|
||||
// integer part that is a single zero, and no trailing zeros below
|
||||
// the decimal point.
|
||||
int pos = 0;
|
||||
int length = number.length();
|
||||
if (number.length() > 15) return false;
|
||||
if (number[pos] == '0') {
|
||||
pos++;
|
||||
} else {
|
||||
while (pos < length &&
|
||||
static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++;
|
||||
}
|
||||
if (length == pos) return true;
|
||||
if (number[pos] != '.') return false;
|
||||
pos++;
|
||||
bool invalid_last_digit = true;
|
||||
while (pos < length) {
|
||||
byte digit = number[pos] - '0';
|
||||
if (digit > '9' - '0') return false;
|
||||
invalid_last_digit = (digit == 0);
|
||||
pos++;
|
||||
}
|
||||
return !invalid_last_digit;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) {
|
||||
// Primitive hash function, almost identical to the one used
|
||||
// for strings (except that it's seeded by the length and ASCII-ness).
|
||||
int length = key.length();
|
||||
uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ;
|
||||
for (int i = 0; i < length; i++) {
|
||||
uint32_t c = key[i];
|
||||
hash = (hash + c) * 1025;
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
bool DuplicateFinder::Match(void* first, void* second) {
|
||||
// Decode lengths.
|
||||
// Length + ASCII-bit is encoded as base 128, most significant heptet first,
|
||||
// with a 8th bit being non-zero while there are more heptets.
|
||||
// The value encodes the number of bytes following, and whether the original
|
||||
// was ASCII.
|
||||
byte* s1 = reinterpret_cast<byte*>(first);
|
||||
byte* s2 = reinterpret_cast<byte*>(second);
|
||||
uint32_t length_ascii_field = 0;
|
||||
byte c1;
|
||||
do {
|
||||
c1 = *s1;
|
||||
if (c1 != *s2) return false;
|
||||
length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f);
|
||||
s1++;
|
||||
s2++;
|
||||
} while ((c1 & 0x80) != 0);
|
||||
int length = static_cast<int>(length_ascii_field >> 1);
|
||||
return memcmp(s1, s2, length) == 0;
|
||||
}
|
||||
|
||||
|
||||
byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes,
|
||||
bool is_ascii) {
|
||||
uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0);
|
||||
backing_store_.StartSequence();
|
||||
// Emit ascii_length as base-128 encoded number, with the 7th bit set
|
||||
// on the byte of every heptet except the last, least significant, one.
|
||||
if (ascii_length >= (1 << 7)) {
|
||||
if (ascii_length >= (1 << 14)) {
|
||||
if (ascii_length >= (1 << 21)) {
|
||||
if (ascii_length >= (1 << 28)) {
|
||||
backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80));
|
||||
}
|
||||
backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u));
|
||||
}
|
||||
backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u));
|
||||
}
|
||||
backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u));
|
||||
}
|
||||
backing_store_.Add(static_cast<byte>(ascii_length & 0x7f));
|
||||
|
||||
backing_store_.AddBlock(bytes);
|
||||
return backing_store_.EndSequence().start();
|
||||
}
|
||||
} } // v8::preparser
|
||||
|
||||
103
deps/v8/src/preparser.h
vendored
103
deps/v8/src/preparser.h
vendored
@@ -28,9 +28,19 @@
|
||||
#ifndef V8_PREPARSER_H
|
||||
#define V8_PREPARSER_H
|
||||
|
||||
#include "token.h"
|
||||
#include "scanner.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
namespace internal {
|
||||
class UnicodeCache;
|
||||
}
|
||||
|
||||
namespace preparser {
|
||||
|
||||
typedef uint8_t byte;
|
||||
|
||||
// Preparsing checks a JavaScript program and emits preparse-data that helps
|
||||
// a later parsing to be faster.
|
||||
// See preparse-data-format.h for the data format.
|
||||
@@ -46,6 +56,53 @@ namespace preparser {
|
||||
|
||||
namespace i = v8::internal;
|
||||
|
||||
class DuplicateFinder {
|
||||
public:
|
||||
explicit DuplicateFinder(i::UnicodeCache* constants)
|
||||
: unicode_constants_(constants),
|
||||
backing_store_(16),
|
||||
map_(&Match) { }
|
||||
|
||||
int AddAsciiSymbol(i::Vector<const char> key, int value);
|
||||
int AddUC16Symbol(i::Vector<const uint16_t> key, int value);
|
||||
// Add a a number literal by converting it (if necessary)
|
||||
// to the string that ToString(ToNumber(literal)) would generate.
|
||||
// and then adding that string with AddAsciiSymbol.
|
||||
// This string is the actual value used as key in an object literal,
|
||||
// and the one that must be different from the other keys.
|
||||
int AddNumber(i::Vector<const char> key, int value);
|
||||
|
||||
private:
|
||||
int AddSymbol(i::Vector<const byte> key, bool is_ascii, int value);
|
||||
// Backs up the key and its length in the backing store.
|
||||
// The backup is stored with a base 127 encoding of the
|
||||
// length (plus a bit saying whether the string is ASCII),
|
||||
// followed by the bytes of the key.
|
||||
byte* BackupKey(i::Vector<const byte> key, bool is_ascii);
|
||||
|
||||
// Compare two encoded keys (both pointing into the backing store)
|
||||
// for having the same base-127 encoded lengths and ASCII-ness,
|
||||
// and then having the same 'length' bytes following.
|
||||
static bool Match(void* first, void* second);
|
||||
// Creates a hash from a sequence of bytes.
|
||||
static uint32_t Hash(i::Vector<const byte> key, bool is_ascii);
|
||||
// Checks whether a string containing a JS number is its canonical
|
||||
// form.
|
||||
static bool IsNumberCanonical(i::Vector<const char> key);
|
||||
|
||||
// Size of buffer. Sufficient for using it to call DoubleToCString in
|
||||
// from conversions.h.
|
||||
static const int kBufferSize = 100;
|
||||
|
||||
i::UnicodeCache* unicode_constants_;
|
||||
// Backing store used to store strings used as hashmap keys.
|
||||
i::SequenceCollector<unsigned char> backing_store_;
|
||||
i::HashMap map_;
|
||||
// Buffer used for string->number->canonical string conversions.
|
||||
char number_buffer_[kBufferSize];
|
||||
};
|
||||
|
||||
|
||||
class PreParser {
|
||||
public:
|
||||
enum PreParseResult {
|
||||
@@ -53,7 +110,7 @@ class PreParser {
|
||||
kPreParseSuccess
|
||||
};
|
||||
|
||||
~PreParser() { }
|
||||
~PreParser() {}
|
||||
|
||||
// Pre-parse the program from the character stream; returns true on
|
||||
// success (even if parsing failed, the pre-parse data successfully
|
||||
@@ -67,6 +124,45 @@ class PreParser {
|
||||
}
|
||||
|
||||
private:
|
||||
// Used to detect duplicates in object literals. Each of the values
|
||||
// kGetterProperty, kSetterProperty and kValueProperty represents
|
||||
// a type of object literal property. When parsing a property, its
|
||||
// type value is stored in the DuplicateFinder for the property name.
|
||||
// Values are chosen so that having intersection bits means the there is
|
||||
// an incompatibility.
|
||||
// I.e., you can add a getter to a property that already has a setter, since
|
||||
// kGetterProperty and kSetterProperty doesn't intersect, but not if it
|
||||
// already has a getter or a value. Adding the getter to an existing
|
||||
// setter will store the value (kGetterProperty | kSetterProperty), which
|
||||
// is incompatible with adding any further properties.
|
||||
enum PropertyType {
|
||||
kNone = 0,
|
||||
// Bit patterns representing different object literal property types.
|
||||
kGetterProperty = 1,
|
||||
kSetterProperty = 2,
|
||||
kValueProperty = 7,
|
||||
// Helper constants.
|
||||
kValueFlag = 4
|
||||
};
|
||||
|
||||
// Checks the type of conflict based on values coming from PropertyType.
|
||||
bool HasConflict(int type1, int type2) { return (type1 & type2) != 0; }
|
||||
bool IsDataDataConflict(int type1, int type2) {
|
||||
return ((type1 & type2) & kValueFlag) != 0;
|
||||
}
|
||||
bool IsDataAccessorConflict(int type1, int type2) {
|
||||
return ((type1 ^ type2) & kValueFlag) != 0;
|
||||
}
|
||||
bool IsAccessorAccessorConflict(int type1, int type2) {
|
||||
return ((type1 | type2) & kValueFlag) == 0;
|
||||
}
|
||||
|
||||
|
||||
void CheckDuplicate(DuplicateFinder* finder,
|
||||
i::Token::Value property,
|
||||
int type,
|
||||
bool* ok);
|
||||
|
||||
// These types form an algebra over syntactic categories that is just
|
||||
// rich enough to let us recognize and propagate the constructs that
|
||||
// are either being counted in the preparser data, or is important
|
||||
@@ -371,6 +467,11 @@ class PreParser {
|
||||
|
||||
// Report syntax error
|
||||
void ReportUnexpectedToken(i::Token::Value token);
|
||||
void ReportMessageAt(i::Scanner::Location location,
|
||||
const char* type,
|
||||
const char* name_opt) {
|
||||
log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
|
||||
}
|
||||
void ReportMessageAt(int start_pos,
|
||||
int end_pos,
|
||||
const char* type,
|
||||
|
||||
15
deps/v8/src/prettyprinter.cc
vendored
15
deps/v8/src/prettyprinter.cc
vendored
@@ -131,11 +131,6 @@ void PrettyPrinter::VisitWithStatement(WithStatement* node) {
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::VisitExitContextStatement(ExitContextStatement* node) {
|
||||
Print("<exit context>");
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) {
|
||||
PrintLabels(node->labels());
|
||||
Print("switch (");
|
||||
@@ -783,11 +778,6 @@ void AstPrinter::VisitWithStatement(WithStatement* node) {
|
||||
}
|
||||
|
||||
|
||||
void AstPrinter::VisitExitContextStatement(ExitContextStatement* node) {
|
||||
PrintIndented("EXIT CONTEXT\n");
|
||||
}
|
||||
|
||||
|
||||
void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
|
||||
IndentedScope indent(this, "SWITCH");
|
||||
PrintLabelsIndented(NULL, node->labels());
|
||||
@@ -1187,11 +1177,6 @@ void JsonAstBuilder::VisitWithStatement(WithStatement* stmt) {
|
||||
}
|
||||
|
||||
|
||||
void JsonAstBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
|
||||
TagScope tag(this, "ExitContextStatement");
|
||||
}
|
||||
|
||||
|
||||
void JsonAstBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
|
||||
TagScope tag(this, "SwitchStatement");
|
||||
}
|
||||
|
||||
1
deps/v8/src/rewriter.cc
vendored
1
deps/v8/src/rewriter.cc
vendored
@@ -208,7 +208,6 @@ void Processor::VisitWithStatement(WithStatement* node) {
|
||||
void Processor::VisitDeclaration(Declaration* node) {}
|
||||
void Processor::VisitEmptyStatement(EmptyStatement* node) {}
|
||||
void Processor::VisitReturnStatement(ReturnStatement* node) {}
|
||||
void Processor::VisitExitContextStatement(ExitContextStatement* node) {}
|
||||
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
|
||||
|
||||
|
||||
|
||||
322
deps/v8/src/runtime.cc
vendored
322
deps/v8/src/runtime.cc
vendored
@@ -2507,7 +2507,7 @@ class ReplacementStringBuilder {
|
||||
class CompiledReplacement {
|
||||
public:
|
||||
CompiledReplacement()
|
||||
: parts_(1), replacement_substrings_(0) {}
|
||||
: parts_(1), replacement_substrings_(0), simple_hint_(false) {}
|
||||
|
||||
void Compile(Handle<String> replacement,
|
||||
int capture_count,
|
||||
@@ -2523,6 +2523,10 @@ class CompiledReplacement {
|
||||
return parts_.length();
|
||||
}
|
||||
|
||||
bool simple_hint() {
|
||||
return simple_hint_;
|
||||
}
|
||||
|
||||
private:
|
||||
enum PartType {
|
||||
SUBJECT_PREFIX = 1,
|
||||
@@ -2581,7 +2585,7 @@ class CompiledReplacement {
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
|
||||
static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
|
||||
Vector<Char> characters,
|
||||
int capture_count,
|
||||
int subject_length) {
|
||||
@@ -2678,14 +2682,17 @@ class CompiledReplacement {
|
||||
if (length > last) {
|
||||
if (last == 0) {
|
||||
parts->Add(ReplacementPart::ReplacementString());
|
||||
return true;
|
||||
} else {
|
||||
parts->Add(ReplacementPart::ReplacementSubString(last, length));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ZoneList<ReplacementPart> parts_;
|
||||
ZoneList<Handle<String> > replacement_substrings_;
|
||||
bool simple_hint_;
|
||||
};
|
||||
|
||||
|
||||
@@ -2697,16 +2704,16 @@ void CompiledReplacement::Compile(Handle<String> replacement,
|
||||
String::FlatContent content = replacement->GetFlatContent();
|
||||
ASSERT(content.IsFlat());
|
||||
if (content.IsAscii()) {
|
||||
ParseReplacementPattern(&parts_,
|
||||
content.ToAsciiVector(),
|
||||
capture_count,
|
||||
subject_length);
|
||||
simple_hint_ = ParseReplacementPattern(&parts_,
|
||||
content.ToAsciiVector(),
|
||||
capture_count,
|
||||
subject_length);
|
||||
} else {
|
||||
ASSERT(content.IsTwoByte());
|
||||
ParseReplacementPattern(&parts_,
|
||||
content.ToUC16Vector(),
|
||||
capture_count,
|
||||
subject_length);
|
||||
simple_hint_ = ParseReplacementPattern(&parts_,
|
||||
content.ToUC16Vector(),
|
||||
capture_count,
|
||||
subject_length);
|
||||
}
|
||||
}
|
||||
Isolate* isolate = replacement->GetIsolate();
|
||||
@@ -2769,6 +2776,170 @@ void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
|
||||
}
|
||||
|
||||
|
||||
void FindAsciiStringIndices(Vector<const char> subject,
|
||||
char pattern,
|
||||
ZoneList<int>* indices,
|
||||
unsigned int limit) {
|
||||
ASSERT(limit > 0);
|
||||
// Collect indices of pattern in subject using memchr.
|
||||
// Stop after finding at most limit values.
|
||||
const char* subject_start = reinterpret_cast<const char*>(subject.start());
|
||||
const char* subject_end = subject_start + subject.length();
|
||||
const char* pos = subject_start;
|
||||
while (limit > 0) {
|
||||
pos = reinterpret_cast<const char*>(
|
||||
memchr(pos, pattern, subject_end - pos));
|
||||
if (pos == NULL) return;
|
||||
indices->Add(static_cast<int>(pos - subject_start));
|
||||
pos++;
|
||||
limit--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename SubjectChar, typename PatternChar>
|
||||
void FindStringIndices(Isolate* isolate,
|
||||
Vector<const SubjectChar> subject,
|
||||
Vector<const PatternChar> pattern,
|
||||
ZoneList<int>* indices,
|
||||
unsigned int limit) {
|
||||
ASSERT(limit > 0);
|
||||
// Collect indices of pattern in subject.
|
||||
// Stop after finding at most limit values.
|
||||
int pattern_length = pattern.length();
|
||||
int index = 0;
|
||||
StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
|
||||
while (limit > 0) {
|
||||
index = search.Search(subject, index);
|
||||
if (index < 0) return;
|
||||
indices->Add(index);
|
||||
index += pattern_length;
|
||||
limit--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FindStringIndicesDispatch(Isolate* isolate,
|
||||
String* subject,
|
||||
String* pattern,
|
||||
ZoneList<int>* indices,
|
||||
unsigned int limit) {
|
||||
{
|
||||
AssertNoAllocation no_gc;
|
||||
String::FlatContent subject_content = subject->GetFlatContent();
|
||||
String::FlatContent pattern_content = pattern->GetFlatContent();
|
||||
ASSERT(subject_content.IsFlat());
|
||||
ASSERT(pattern_content.IsFlat());
|
||||
if (subject_content.IsAscii()) {
|
||||
Vector<const char> subject_vector = subject_content.ToAsciiVector();
|
||||
if (pattern_content.IsAscii()) {
|
||||
Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
|
||||
if (pattern_vector.length() == 1) {
|
||||
FindAsciiStringIndices(subject_vector,
|
||||
pattern_vector[0],
|
||||
indices,
|
||||
limit);
|
||||
} else {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_vector,
|
||||
indices,
|
||||
limit);
|
||||
}
|
||||
} else {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_content.ToUC16Vector(),
|
||||
indices,
|
||||
limit);
|
||||
}
|
||||
} else {
|
||||
Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
|
||||
if (pattern->IsAsciiRepresentation()) {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_content.ToAsciiVector(),
|
||||
indices,
|
||||
limit);
|
||||
} else {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_content.ToUC16Vector(),
|
||||
indices,
|
||||
limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ResultSeqString>
|
||||
MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
|
||||
Isolate* isolate,
|
||||
Handle<String> subject,
|
||||
Handle<JSRegExp> pattern_regexp,
|
||||
Handle<String> replacement) {
|
||||
ASSERT(subject->IsFlat());
|
||||
ASSERT(replacement->IsFlat());
|
||||
|
||||
ZoneScope zone_space(isolate, DELETE_ON_EXIT);
|
||||
ZoneList<int> indices(8);
|
||||
ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
|
||||
String* pattern =
|
||||
String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
|
||||
int subject_len = subject->length();
|
||||
int pattern_len = pattern->length();
|
||||
int replacement_len = replacement->length();
|
||||
|
||||
FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
|
||||
|
||||
int matches = indices.length();
|
||||
if (matches == 0) return *subject;
|
||||
|
||||
int result_len = (replacement_len - pattern_len) * matches + subject_len;
|
||||
int subject_pos = 0;
|
||||
int result_pos = 0;
|
||||
|
||||
Handle<ResultSeqString> result;
|
||||
if (ResultSeqString::kHasAsciiEncoding) {
|
||||
result = Handle<ResultSeqString>::cast(
|
||||
isolate->factory()->NewRawAsciiString(result_len));
|
||||
} else {
|
||||
result = Handle<ResultSeqString>::cast(
|
||||
isolate->factory()->NewRawTwoByteString(result_len));
|
||||
}
|
||||
|
||||
for (int i = 0; i < matches; i++) {
|
||||
// Copy non-matched subject content.
|
||||
if (subject_pos < indices.at(i)) {
|
||||
String::WriteToFlat(*subject,
|
||||
result->GetChars() + result_pos,
|
||||
subject_pos,
|
||||
indices.at(i));
|
||||
result_pos += indices.at(i) - subject_pos;
|
||||
}
|
||||
|
||||
// Replace match.
|
||||
if (replacement_len > 0) {
|
||||
String::WriteToFlat(*replacement,
|
||||
result->GetChars() + result_pos,
|
||||
0,
|
||||
replacement_len);
|
||||
result_pos += replacement_len;
|
||||
}
|
||||
|
||||
subject_pos = indices.at(i) + pattern_len;
|
||||
}
|
||||
// Add remaining subject content at the end.
|
||||
if (subject_pos < subject_len) {
|
||||
String::WriteToFlat(*subject,
|
||||
result->GetChars() + result_pos,
|
||||
subject_pos,
|
||||
subject_len);
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
|
||||
Isolate* isolate,
|
||||
@@ -2808,6 +2979,20 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
|
||||
|
||||
bool is_global = regexp_handle->GetFlags().is_global();
|
||||
|
||||
// Shortcut for simple non-regexp global replacements
|
||||
if (is_global &&
|
||||
regexp->TypeTag() == JSRegExp::ATOM &&
|
||||
compiled_replacement.simple_hint()) {
|
||||
if (subject_handle->HasOnlyAsciiChars() &&
|
||||
replacement_handle->HasOnlyAsciiChars()) {
|
||||
return StringReplaceStringWithString<SeqAsciiString>(
|
||||
isolate, subject_handle, regexp_handle, replacement_handle);
|
||||
} else {
|
||||
return StringReplaceStringWithString<SeqTwoByteString>(
|
||||
isolate, subject_handle, regexp_handle, replacement_handle);
|
||||
}
|
||||
}
|
||||
|
||||
// Guessing the number of parts that the final result string is built
|
||||
// from. Global regexps can match any number of times, so we guess
|
||||
// conservatively.
|
||||
@@ -2893,6 +3078,20 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
|
||||
|
||||
Handle<String> subject_handle(subject);
|
||||
Handle<JSRegExp> regexp_handle(regexp);
|
||||
|
||||
// Shortcut for simple non-regexp global replacements
|
||||
if (regexp_handle->GetFlags().is_global() &&
|
||||
regexp_handle->TypeTag() == JSRegExp::ATOM) {
|
||||
Handle<String> empty_string_handle(HEAP->empty_string());
|
||||
if (subject_handle->HasOnlyAsciiChars()) {
|
||||
return StringReplaceStringWithString<SeqAsciiString>(
|
||||
isolate, subject_handle, regexp_handle, empty_string_handle);
|
||||
} else {
|
||||
return StringReplaceStringWithString<SeqTwoByteString>(
|
||||
isolate, subject_handle, regexp_handle, empty_string_handle);
|
||||
}
|
||||
}
|
||||
|
||||
Handle<JSArray> last_match_info_handle(last_match_info);
|
||||
Handle<Object> match = RegExpImpl::Exec(regexp_handle,
|
||||
subject_handle,
|
||||
@@ -5930,49 +6129,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
|
||||
}
|
||||
|
||||
|
||||
void FindAsciiStringIndices(Vector<const char> subject,
|
||||
char pattern,
|
||||
ZoneList<int>* indices,
|
||||
unsigned int limit) {
|
||||
ASSERT(limit > 0);
|
||||
// Collect indices of pattern in subject using memchr.
|
||||
// Stop after finding at most limit values.
|
||||
const char* subject_start = reinterpret_cast<const char*>(subject.start());
|
||||
const char* subject_end = subject_start + subject.length();
|
||||
const char* pos = subject_start;
|
||||
while (limit > 0) {
|
||||
pos = reinterpret_cast<const char*>(
|
||||
memchr(pos, pattern, subject_end - pos));
|
||||
if (pos == NULL) return;
|
||||
indices->Add(static_cast<int>(pos - subject_start));
|
||||
pos++;
|
||||
limit--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename SubjectChar, typename PatternChar>
|
||||
void FindStringIndices(Isolate* isolate,
|
||||
Vector<const SubjectChar> subject,
|
||||
Vector<const PatternChar> pattern,
|
||||
ZoneList<int>* indices,
|
||||
unsigned int limit) {
|
||||
ASSERT(limit > 0);
|
||||
// Collect indices of pattern in subject.
|
||||
// Stop after finding at most limit values.
|
||||
int pattern_length = pattern.length();
|
||||
int index = 0;
|
||||
StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
|
||||
while (limit > 0) {
|
||||
index = search.Search(subject, index);
|
||||
if (index < 0) return;
|
||||
indices->Add(index);
|
||||
index += pattern_length;
|
||||
limit--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
|
||||
ASSERT(args.length() == 3);
|
||||
HandleScope handle_scope(isolate);
|
||||
@@ -6012,53 +6168,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
|
||||
ZoneList<int> indices(initial_capacity);
|
||||
if (!pattern->IsFlat()) FlattenString(pattern);
|
||||
|
||||
// No allocation block.
|
||||
{
|
||||
AssertNoAllocation no_gc;
|
||||
String::FlatContent subject_content = subject->GetFlatContent();
|
||||
String::FlatContent pattern_content = pattern->GetFlatContent();
|
||||
ASSERT(subject_content.IsFlat());
|
||||
ASSERT(pattern_content.IsFlat());
|
||||
if (subject_content.IsAscii()) {
|
||||
Vector<const char> subject_vector = subject_content.ToAsciiVector();
|
||||
if (pattern_content.IsAscii()) {
|
||||
Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
|
||||
if (pattern_vector.length() == 1) {
|
||||
FindAsciiStringIndices(subject_vector,
|
||||
pattern_vector[0],
|
||||
&indices,
|
||||
limit);
|
||||
} else {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_vector,
|
||||
&indices,
|
||||
limit);
|
||||
}
|
||||
} else {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_content.ToUC16Vector(),
|
||||
&indices,
|
||||
limit);
|
||||
}
|
||||
} else {
|
||||
Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
|
||||
if (pattern->IsAsciiRepresentation()) {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_content.ToAsciiVector(),
|
||||
&indices,
|
||||
limit);
|
||||
} else {
|
||||
FindStringIndices(isolate,
|
||||
subject_vector,
|
||||
pattern_content.ToUC16Vector(),
|
||||
&indices,
|
||||
limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
|
||||
|
||||
if (static_cast<uint32_t>(indices.length()) < limit) {
|
||||
indices.Add(subject_length);
|
||||
@@ -6091,11 +6201,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
|
||||
}
|
||||
|
||||
if (limit == 0xffffffffu) {
|
||||
StringSplitCache::Enter(isolate->heap(),
|
||||
isolate->heap()->string_split_cache(),
|
||||
*subject,
|
||||
*pattern,
|
||||
*elements);
|
||||
if (result->HasFastElements()) {
|
||||
StringSplitCache::Enter(isolate->heap(),
|
||||
isolate->heap()->string_split_cache(),
|
||||
*subject,
|
||||
*pattern,
|
||||
*elements);
|
||||
}
|
||||
}
|
||||
|
||||
return *result;
|
||||
|
||||
1090
deps/v8/src/scanner-base.cc
vendored
1090
deps/v8/src/scanner-base.cc
vendored
File diff suppressed because it is too large
Load Diff
562
deps/v8/src/scanner-base.h
vendored
562
deps/v8/src/scanner-base.h
vendored
@@ -1,562 +0,0 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Features shared by parsing and pre-parsing scanners.
|
||||
|
||||
#ifndef V8_SCANNER_BASE_H_
|
||||
#define V8_SCANNER_BASE_H_
|
||||
|
||||
#include "allocation.h"
|
||||
#include "char-predicates.h"
|
||||
#include "checks.h"
|
||||
#include "globals.h"
|
||||
#include "token.h"
|
||||
#include "unicode-inl.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Returns the value (0 .. 15) of a hexadecimal character c.
|
||||
// If c is not a legal hexadecimal character, returns a value < 0.
|
||||
inline int HexValue(uc32 c) {
|
||||
c -= '0';
|
||||
if (static_cast<unsigned>(c) <= 9) return c;
|
||||
c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
|
||||
if (static_cast<unsigned>(c) <= 5) return c + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Buffered stream of characters, using an internal UC16 buffer.
|
||||
|
||||
class UC16CharacterStream {
|
||||
public:
|
||||
UC16CharacterStream() : pos_(0) { }
|
||||
virtual ~UC16CharacterStream() { }
|
||||
|
||||
// Returns and advances past the next UC16 character in the input
|
||||
// stream. If there are no more characters, it returns a negative
|
||||
// value.
|
||||
inline uc32 Advance() {
|
||||
if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
|
||||
pos_++;
|
||||
return static_cast<uc32>(*(buffer_cursor_++));
|
||||
}
|
||||
// Note: currently the following increment is necessary to avoid a
|
||||
// parser problem! The scanner treats the final kEndOfInput as
|
||||
// a character with a position, and does math relative to that
|
||||
// position.
|
||||
pos_++;
|
||||
|
||||
return kEndOfInput;
|
||||
}
|
||||
|
||||
// Return the current position in the character stream.
|
||||
// Starts at zero.
|
||||
inline unsigned pos() const { return pos_; }
|
||||
|
||||
// Skips forward past the next character_count UC16 characters
|
||||
// in the input, or until the end of input if that comes sooner.
|
||||
// Returns the number of characters actually skipped. If less
|
||||
// than character_count,
|
||||
inline unsigned SeekForward(unsigned character_count) {
|
||||
unsigned buffered_chars =
|
||||
static_cast<unsigned>(buffer_end_ - buffer_cursor_);
|
||||
if (character_count <= buffered_chars) {
|
||||
buffer_cursor_ += character_count;
|
||||
pos_ += character_count;
|
||||
return character_count;
|
||||
}
|
||||
return SlowSeekForward(character_count);
|
||||
}
|
||||
|
||||
// Pushes back the most recently read UC16 character (or negative
|
||||
// value if at end of input), i.e., the value returned by the most recent
|
||||
// call to Advance.
|
||||
// Must not be used right after calling SeekForward.
|
||||
virtual void PushBack(int32_t character) = 0;
|
||||
|
||||
protected:
|
||||
static const uc32 kEndOfInput = -1;
|
||||
|
||||
// Ensures that the buffer_cursor_ points to the character at
|
||||
// position pos_ of the input, if possible. If the position
|
||||
// is at or after the end of the input, return false. If there
|
||||
// are more characters available, return true.
|
||||
virtual bool ReadBlock() = 0;
|
||||
virtual unsigned SlowSeekForward(unsigned character_count) = 0;
|
||||
|
||||
const uc16* buffer_cursor_;
|
||||
const uc16* buffer_end_;
|
||||
unsigned pos_;
|
||||
};
|
||||
|
||||
|
||||
class UnicodeCache {
|
||||
// ---------------------------------------------------------------------
|
||||
// Caching predicates used by scanners.
|
||||
public:
|
||||
UnicodeCache() {}
|
||||
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
|
||||
|
||||
StaticResource<Utf8Decoder>* utf8_decoder() {
|
||||
return &utf8_decoder_;
|
||||
}
|
||||
|
||||
bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
|
||||
bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
|
||||
bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
|
||||
bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
|
||||
|
||||
private:
|
||||
|
||||
unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
|
||||
unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
|
||||
unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
|
||||
unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
|
||||
StaticResource<Utf8Decoder> utf8_decoder_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(UnicodeCache);
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// LiteralBuffer - Collector of chars of literals.
|
||||
|
||||
class LiteralBuffer {
|
||||
public:
|
||||
LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { }
|
||||
|
||||
~LiteralBuffer() {
|
||||
if (backing_store_.length() > 0) {
|
||||
backing_store_.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
inline void AddChar(uc16 character) {
|
||||
if (position_ >= backing_store_.length()) ExpandBuffer();
|
||||
if (is_ascii_) {
|
||||
if (character < kMaxAsciiCharCodeU) {
|
||||
backing_store_[position_] = static_cast<byte>(character);
|
||||
position_ += kASCIISize;
|
||||
return;
|
||||
}
|
||||
ConvertToUC16();
|
||||
}
|
||||
*reinterpret_cast<uc16*>(&backing_store_[position_]) = character;
|
||||
position_ += kUC16Size;
|
||||
}
|
||||
|
||||
bool is_ascii() { return is_ascii_; }
|
||||
|
||||
Vector<const uc16> uc16_literal() {
|
||||
ASSERT(!is_ascii_);
|
||||
ASSERT((position_ & 0x1) == 0);
|
||||
return Vector<const uc16>(
|
||||
reinterpret_cast<const uc16*>(backing_store_.start()),
|
||||
position_ >> 1);
|
||||
}
|
||||
|
||||
Vector<const char> ascii_literal() {
|
||||
ASSERT(is_ascii_);
|
||||
return Vector<const char>(
|
||||
reinterpret_cast<const char*>(backing_store_.start()),
|
||||
position_);
|
||||
}
|
||||
|
||||
int length() {
|
||||
return is_ascii_ ? position_ : (position_ >> 1);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
position_ = 0;
|
||||
is_ascii_ = true;
|
||||
}
|
||||
private:
|
||||
static const int kInitialCapacity = 16;
|
||||
static const int kGrowthFactory = 4;
|
||||
static const int kMinConversionSlack = 256;
|
||||
static const int kMaxGrowth = 1 * MB;
|
||||
inline int NewCapacity(int min_capacity) {
|
||||
int capacity = Max(min_capacity, backing_store_.length());
|
||||
int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
|
||||
return new_capacity;
|
||||
}
|
||||
|
||||
void ExpandBuffer() {
|
||||
Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
|
||||
memcpy(new_store.start(), backing_store_.start(), position_);
|
||||
backing_store_.Dispose();
|
||||
backing_store_ = new_store;
|
||||
}
|
||||
|
||||
void ConvertToUC16() {
|
||||
ASSERT(is_ascii_);
|
||||
Vector<byte> new_store;
|
||||
int new_content_size = position_ * kUC16Size;
|
||||
if (new_content_size >= backing_store_.length()) {
|
||||
// Ensure room for all currently read characters as UC16 as well
|
||||
// as the character about to be stored.
|
||||
new_store = Vector<byte>::New(NewCapacity(new_content_size));
|
||||
} else {
|
||||
new_store = backing_store_;
|
||||
}
|
||||
char* src = reinterpret_cast<char*>(backing_store_.start());
|
||||
uc16* dst = reinterpret_cast<uc16*>(new_store.start());
|
||||
for (int i = position_ - 1; i >= 0; i--) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
if (new_store.start() != backing_store_.start()) {
|
||||
backing_store_.Dispose();
|
||||
backing_store_ = new_store;
|
||||
}
|
||||
position_ = new_content_size;
|
||||
is_ascii_ = false;
|
||||
}
|
||||
|
||||
bool is_ascii_;
|
||||
int position_;
|
||||
Vector<byte> backing_store_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Scanner base-class.
|
||||
|
||||
// Generic functionality used by both JSON and JavaScript scanners.
|
||||
class Scanner {
|
||||
public:
|
||||
// -1 is outside of the range of any real source code.
|
||||
static const int kNoOctalLocation = -1;
|
||||
|
||||
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
|
||||
|
||||
class LiteralScope {
|
||||
public:
|
||||
explicit LiteralScope(Scanner* self);
|
||||
~LiteralScope();
|
||||
void Complete();
|
||||
|
||||
private:
|
||||
Scanner* scanner_;
|
||||
bool complete_;
|
||||
};
|
||||
|
||||
explicit Scanner(UnicodeCache* scanner_contants);
|
||||
|
||||
// Returns the current token again.
|
||||
Token::Value current_token() { return current_.token; }
|
||||
|
||||
// One token look-ahead (past the token returned by Next()).
|
||||
Token::Value peek() const { return next_.token; }
|
||||
|
||||
struct Location {
|
||||
Location(int b, int e) : beg_pos(b), end_pos(e) { }
|
||||
Location() : beg_pos(0), end_pos(0) { }
|
||||
|
||||
bool IsValid() const {
|
||||
return beg_pos >= 0 && end_pos >= beg_pos;
|
||||
}
|
||||
|
||||
static Location invalid() { return Location(-1, -1); }
|
||||
|
||||
int beg_pos;
|
||||
int end_pos;
|
||||
};
|
||||
|
||||
// Returns the location information for the current token
|
||||
// (the token returned by Next()).
|
||||
Location location() const { return current_.location; }
|
||||
Location peek_location() const { return next_.location; }
|
||||
|
||||
// Returns the literal string, if any, for the current token (the
|
||||
// token returned by Next()). The string is 0-terminated and in
|
||||
// UTF-8 format; they may contain 0-characters. Literal strings are
|
||||
// collected for identifiers, strings, and numbers.
|
||||
// These functions only give the correct result if the literal
|
||||
// was scanned between calls to StartLiteral() and TerminateLiteral().
|
||||
bool is_literal_ascii() {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->is_ascii();
|
||||
}
|
||||
Vector<const char> literal_ascii_string() {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->ascii_literal();
|
||||
}
|
||||
Vector<const uc16> literal_uc16_string() {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->uc16_literal();
|
||||
}
|
||||
int literal_length() const {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->length();
|
||||
}
|
||||
|
||||
bool literal_contains_escapes() const {
|
||||
Location location = current_.location;
|
||||
int source_length = (location.end_pos - location.beg_pos);
|
||||
if (current_.token == Token::STRING) {
|
||||
// Subtract delimiters.
|
||||
source_length -= 2;
|
||||
}
|
||||
return current_.literal_chars->length() != source_length;
|
||||
}
|
||||
|
||||
// Returns the literal string for the next token (the token that
|
||||
// would be returned if Next() were called).
|
||||
bool is_next_literal_ascii() {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->is_ascii();
|
||||
}
|
||||
Vector<const char> next_literal_ascii_string() {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->ascii_literal();
|
||||
}
|
||||
Vector<const uc16> next_literal_uc16_string() {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->uc16_literal();
|
||||
}
|
||||
int next_literal_length() const {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->length();
|
||||
}
|
||||
|
||||
static const int kCharacterLookaheadBufferSize = 1;
|
||||
|
||||
protected:
|
||||
// The current and look-ahead token.
|
||||
struct TokenDesc {
|
||||
Token::Value token;
|
||||
Location location;
|
||||
LiteralBuffer* literal_chars;
|
||||
};
|
||||
|
||||
// Call this after setting source_ to the input.
|
||||
void Init() {
|
||||
// Set c0_ (one character ahead)
|
||||
STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
|
||||
Advance();
|
||||
// Initialize current_ to not refer to a literal.
|
||||
current_.literal_chars = NULL;
|
||||
}
|
||||
|
||||
// Literal buffer support
|
||||
inline void StartLiteral() {
|
||||
LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ?
|
||||
&literal_buffer2_ : &literal_buffer1_;
|
||||
free_buffer->Reset();
|
||||
next_.literal_chars = free_buffer;
|
||||
}
|
||||
|
||||
inline void AddLiteralChar(uc32 c) {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
next_.literal_chars->AddChar(c);
|
||||
}
|
||||
|
||||
// Complete scanning of a literal.
|
||||
inline void TerminateLiteral() {
|
||||
// Does nothing in the current implementation.
|
||||
}
|
||||
|
||||
// Stops scanning of a literal and drop the collected characters,
|
||||
// e.g., due to an encountered error.
|
||||
inline void DropLiteral() {
|
||||
next_.literal_chars = NULL;
|
||||
}
|
||||
|
||||
inline void AddLiteralCharAdvance() {
|
||||
AddLiteralChar(c0_);
|
||||
Advance();
|
||||
}
|
||||
|
||||
// Low-level scanning support.
|
||||
void Advance() { c0_ = source_->Advance(); }
|
||||
void PushBack(uc32 ch) {
|
||||
source_->PushBack(c0_);
|
||||
c0_ = ch;
|
||||
}
|
||||
|
||||
inline Token::Value Select(Token::Value tok) {
|
||||
Advance();
|
||||
return tok;
|
||||
}
|
||||
|
||||
inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
|
||||
Advance();
|
||||
if (c0_ == next) {
|
||||
Advance();
|
||||
return then;
|
||||
} else {
|
||||
return else_;
|
||||
}
|
||||
}
|
||||
|
||||
uc32 ScanHexNumber(int expected_length);
|
||||
|
||||
// Return the current source position.
|
||||
int source_pos() {
|
||||
return source_->pos() - kCharacterLookaheadBufferSize;
|
||||
}
|
||||
|
||||
UnicodeCache* unicode_cache_;
|
||||
|
||||
// Buffers collecting literal strings, numbers, etc.
|
||||
LiteralBuffer literal_buffer1_;
|
||||
LiteralBuffer literal_buffer2_;
|
||||
|
||||
TokenDesc current_; // desc for current token (as returned by Next())
|
||||
TokenDesc next_; // desc for next token (one token look-ahead)
|
||||
|
||||
// Input stream. Must be initialized to an UC16CharacterStream.
|
||||
UC16CharacterStream* source_;
|
||||
|
||||
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
|
||||
uc32 c0_;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// JavaScriptScanner - base logic for JavaScript scanning.
|
||||
|
||||
class JavaScriptScanner : public Scanner {
|
||||
public:
|
||||
// A LiteralScope that disables recording of some types of JavaScript
|
||||
// literals. If the scanner is configured to not record the specific
|
||||
// type of literal, the scope will not call StartLiteral.
|
||||
class LiteralScope {
|
||||
public:
|
||||
explicit LiteralScope(JavaScriptScanner* self)
|
||||
: scanner_(self), complete_(false) {
|
||||
scanner_->StartLiteral();
|
||||
}
|
||||
~LiteralScope() {
|
||||
if (!complete_) scanner_->DropLiteral();
|
||||
}
|
||||
void Complete() {
|
||||
scanner_->TerminateLiteral();
|
||||
complete_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
JavaScriptScanner* scanner_;
|
||||
bool complete_;
|
||||
};
|
||||
|
||||
explicit JavaScriptScanner(UnicodeCache* scanner_contants);
|
||||
|
||||
void Initialize(UC16CharacterStream* source);
|
||||
|
||||
// Returns the next token.
|
||||
Token::Value Next();
|
||||
|
||||
// Returns true if there was a line terminator before the peek'ed token,
|
||||
// possibly inside a multi-line comment.
|
||||
bool HasAnyLineTerminatorBeforeNext() const {
|
||||
return has_line_terminator_before_next_ ||
|
||||
has_multiline_comment_before_next_;
|
||||
}
|
||||
|
||||
// Scans the input as a regular expression pattern, previous
|
||||
// character(s) must be /(=). Returns true if a pattern is scanned.
|
||||
bool ScanRegExpPattern(bool seen_equal);
|
||||
// Returns true if regexp flags are scanned (always since flags can
|
||||
// be empty).
|
||||
bool ScanRegExpFlags();
|
||||
|
||||
// Tells whether the buffer contains an identifier (no escapes).
|
||||
// Used for checking if a property name is an identifier.
|
||||
static bool IsIdentifier(unibrow::CharacterStream* buffer);
|
||||
|
||||
// Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
|
||||
uc32 ScanOctalEscape(uc32 c, int length);
|
||||
|
||||
// Returns the location of the last seen octal literal
|
||||
Location octal_position() const { return octal_pos_; }
|
||||
void clear_octal_position() { octal_pos_ = Location::invalid(); }
|
||||
|
||||
// Seek forward to the given position. This operation does not
|
||||
// work in general, for instance when there are pushed back
|
||||
// characters, but works for seeking forward until simple delimiter
|
||||
// tokens, which is what it is used for.
|
||||
void SeekForward(int pos);
|
||||
|
||||
bool HarmonyBlockScoping() const {
|
||||
return harmony_block_scoping_;
|
||||
}
|
||||
void SetHarmonyBlockScoping(bool block_scoping) {
|
||||
harmony_block_scoping_ = block_scoping;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
bool SkipWhiteSpace();
|
||||
Token::Value SkipSingleLineComment();
|
||||
Token::Value SkipMultiLineComment();
|
||||
|
||||
// Scans a single JavaScript token.
|
||||
void Scan();
|
||||
|
||||
void ScanDecimalDigits();
|
||||
Token::Value ScanNumber(bool seen_period);
|
||||
Token::Value ScanIdentifierOrKeyword();
|
||||
Token::Value ScanIdentifierSuffix(LiteralScope* literal);
|
||||
|
||||
void ScanEscape();
|
||||
Token::Value ScanString();
|
||||
|
||||
// Scans a possible HTML comment -- begins with '<!'.
|
||||
Token::Value ScanHtmlComment();
|
||||
|
||||
// Decodes a unicode escape-sequence which is part of an identifier.
|
||||
// If the escape sequence cannot be decoded the result is kBadChar.
|
||||
uc32 ScanIdentifierUnicodeEscape();
|
||||
// Recognizes a uniocde escape-sequence and adds its characters,
|
||||
// uninterpreted, to the current literal. Used for parsing RegExp
|
||||
// flags.
|
||||
bool ScanLiteralUnicodeEscape();
|
||||
|
||||
// Start position of the octal literal last scanned.
|
||||
Location octal_pos_;
|
||||
|
||||
// Whether there is a line terminator whitespace character after
|
||||
// the current token, and before the next. Does not count newlines
|
||||
// inside multiline comments.
|
||||
bool has_line_terminator_before_next_;
|
||||
// Whether there is a multi-line comment that contains a
|
||||
// line-terminator after the current token, and before the next.
|
||||
bool has_multiline_comment_before_next_;
|
||||
// Whether we scan 'let' as a keyword for harmony block scoped
|
||||
// let bindings.
|
||||
bool harmony_block_scoping_;
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_SCANNER_BASE_H_
|
||||
328
deps/v8/src/scanner-character-streams.cc
vendored
Normal file
328
deps/v8/src/scanner-character-streams.cc
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
// Copyright 2011 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 "v8.h"
|
||||
|
||||
#include "scanner-character-streams.h"
|
||||
|
||||
#include "ast.h"
|
||||
#include "handles.h"
|
||||
#include "unicode-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// BufferedUC16CharacterStreams
|
||||
|
||||
BufferedUC16CharacterStream::BufferedUC16CharacterStream()
|
||||
: UC16CharacterStream(),
|
||||
pushback_limit_(NULL) {
|
||||
// Initialize buffer as being empty. First read will fill the buffer.
|
||||
buffer_cursor_ = buffer_;
|
||||
buffer_end_ = buffer_;
|
||||
}
|
||||
|
||||
BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { }
|
||||
|
||||
void BufferedUC16CharacterStream::PushBack(uc32 character) {
|
||||
if (character == kEndOfInput) {
|
||||
pos_--;
|
||||
return;
|
||||
}
|
||||
if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) {
|
||||
// buffer_ is writable, buffer_cursor_ is const pointer.
|
||||
buffer_[--buffer_cursor_ - buffer_] = static_cast<uc16>(character);
|
||||
pos_--;
|
||||
return;
|
||||
}
|
||||
SlowPushBack(static_cast<uc16>(character));
|
||||
}
|
||||
|
||||
|
||||
void BufferedUC16CharacterStream::SlowPushBack(uc16 character) {
|
||||
// In pushback mode, the end of the buffer contains pushback,
|
||||
// and the start of the buffer (from buffer start to pushback_limit_)
|
||||
// contains valid data that comes just after the pushback.
|
||||
// We NULL the pushback_limit_ if pushing all the way back to the
|
||||
// start of the buffer.
|
||||
|
||||
if (pushback_limit_ == NULL) {
|
||||
// Enter pushback mode.
|
||||
pushback_limit_ = buffer_end_;
|
||||
buffer_end_ = buffer_ + kBufferSize;
|
||||
buffer_cursor_ = buffer_end_;
|
||||
}
|
||||
// Ensure that there is room for at least one pushback.
|
||||
ASSERT(buffer_cursor_ > buffer_);
|
||||
ASSERT(pos_ > 0);
|
||||
buffer_[--buffer_cursor_ - buffer_] = character;
|
||||
if (buffer_cursor_ == buffer_) {
|
||||
pushback_limit_ = NULL;
|
||||
} else if (buffer_cursor_ < pushback_limit_) {
|
||||
pushback_limit_ = buffer_cursor_;
|
||||
}
|
||||
pos_--;
|
||||
}
|
||||
|
||||
|
||||
bool BufferedUC16CharacterStream::ReadBlock() {
|
||||
buffer_cursor_ = buffer_;
|
||||
if (pushback_limit_ != NULL) {
|
||||
// Leave pushback mode.
|
||||
buffer_end_ = pushback_limit_;
|
||||
pushback_limit_ = NULL;
|
||||
// If there were any valid characters left at the
|
||||
// start of the buffer, use those.
|
||||
if (buffer_cursor_ < buffer_end_) return true;
|
||||
// Otherwise read a new block.
|
||||
}
|
||||
unsigned length = FillBuffer(pos_, kBufferSize);
|
||||
buffer_end_ = buffer_ + length;
|
||||
return length > 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) {
|
||||
// Leave pushback mode (i.e., ignore that there might be valid data
|
||||
// in the buffer before the pushback_limit_ point).
|
||||
pushback_limit_ = NULL;
|
||||
return BufferSeekForward(delta);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// GenericStringUC16CharacterStream
|
||||
|
||||
|
||||
GenericStringUC16CharacterStream::GenericStringUC16CharacterStream(
|
||||
Handle<String> data,
|
||||
unsigned start_position,
|
||||
unsigned end_position)
|
||||
: string_(data),
|
||||
length_(end_position) {
|
||||
ASSERT(end_position >= start_position);
|
||||
buffer_cursor_ = buffer_;
|
||||
buffer_end_ = buffer_;
|
||||
pos_ = start_position;
|
||||
}
|
||||
|
||||
|
||||
GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { }
|
||||
|
||||
|
||||
unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) {
|
||||
unsigned old_pos = pos_;
|
||||
pos_ = Min(pos_ + delta, length_);
|
||||
ReadBlock();
|
||||
return pos_ - old_pos;
|
||||
}
|
||||
|
||||
|
||||
unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos,
|
||||
unsigned length) {
|
||||
if (from_pos >= length_) return 0;
|
||||
if (from_pos + length > length_) {
|
||||
length = length_ - from_pos;
|
||||
}
|
||||
String::WriteToFlat<uc16>(*string_, buffer_, from_pos, from_pos + length);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Utf8ToUC16CharacterStream
|
||||
Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data,
|
||||
unsigned length)
|
||||
: BufferedUC16CharacterStream(),
|
||||
raw_data_(data),
|
||||
raw_data_length_(length),
|
||||
raw_data_pos_(0),
|
||||
raw_character_position_(0) {
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
|
||||
Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { }
|
||||
|
||||
|
||||
unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) {
|
||||
unsigned old_pos = pos_;
|
||||
unsigned target_pos = pos_ + delta;
|
||||
SetRawPosition(target_pos);
|
||||
pos_ = raw_character_position_;
|
||||
ReadBlock();
|
||||
return pos_ - old_pos;
|
||||
}
|
||||
|
||||
|
||||
unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position,
|
||||
unsigned length) {
|
||||
static const unibrow::uchar kMaxUC16Character = 0xffff;
|
||||
SetRawPosition(char_position);
|
||||
if (raw_character_position_ != char_position) {
|
||||
// char_position was not a valid position in the stream (hit the end
|
||||
// while spooling to it).
|
||||
return 0u;
|
||||
}
|
||||
unsigned i = 0;
|
||||
while (i < length) {
|
||||
if (raw_data_pos_ == raw_data_length_) break;
|
||||
unibrow::uchar c = raw_data_[raw_data_pos_];
|
||||
if (c <= unibrow::Utf8::kMaxOneByteChar) {
|
||||
raw_data_pos_++;
|
||||
} else {
|
||||
c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,
|
||||
raw_data_length_ - raw_data_pos_,
|
||||
&raw_data_pos_);
|
||||
// Don't allow characters outside of the BMP.
|
||||
if (c > kMaxUC16Character) {
|
||||
c = unibrow::Utf8::kBadChar;
|
||||
}
|
||||
}
|
||||
buffer_[i++] = static_cast<uc16>(c);
|
||||
}
|
||||
raw_character_position_ = char_position + i;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static const byte kUtf8MultiByteMask = 0xC0;
|
||||
static const byte kUtf8MultiByteCharStart = 0xC0;
|
||||
static const byte kUtf8MultiByteCharFollower = 0x80;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool IsUtf8MultiCharacterStart(byte first_byte) {
|
||||
return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool IsUtf8MultiCharacterFollower(byte later_byte) {
|
||||
return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower;
|
||||
}
|
||||
|
||||
|
||||
// Move the cursor back to point at the preceding UTF-8 character start
|
||||
// in the buffer.
|
||||
static inline void Utf8CharacterBack(const byte* buffer, unsigned* cursor) {
|
||||
byte character = buffer[--*cursor];
|
||||
if (character > unibrow::Utf8::kMaxOneByteChar) {
|
||||
ASSERT(IsUtf8MultiCharacterFollower(character));
|
||||
// Last byte of a multi-byte character encoding. Step backwards until
|
||||
// pointing to the first byte of the encoding, recognized by having the
|
||||
// top two bits set.
|
||||
while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { }
|
||||
ASSERT(IsUtf8MultiCharacterStart(buffer[*cursor]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Move the cursor forward to point at the next following UTF-8 character start
|
||||
// in the buffer.
|
||||
static inline void Utf8CharacterForward(const byte* buffer, unsigned* cursor) {
|
||||
byte character = buffer[(*cursor)++];
|
||||
if (character > unibrow::Utf8::kMaxOneByteChar) {
|
||||
// First character of a multi-byte character encoding.
|
||||
// The number of most-significant one-bits determines the length of the
|
||||
// encoding:
|
||||
// 110..... - (0xCx, 0xDx) one additional byte (minimum).
|
||||
// 1110.... - (0xEx) two additional bytes.
|
||||
// 11110... - (0xFx) three additional bytes (maximum).
|
||||
ASSERT(IsUtf8MultiCharacterStart(character));
|
||||
// Additional bytes is:
|
||||
// 1 if value in range 0xC0 .. 0xDF.
|
||||
// 2 if value in range 0xE0 .. 0xEF.
|
||||
// 3 if value in range 0xF0 .. 0xF7.
|
||||
// Encode that in a single value.
|
||||
unsigned additional_bytes =
|
||||
((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03;
|
||||
*cursor += additional_bytes;
|
||||
ASSERT(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) {
|
||||
if (raw_character_position_ > target_position) {
|
||||
// Spool backwards in utf8 buffer.
|
||||
do {
|
||||
Utf8CharacterBack(raw_data_, &raw_data_pos_);
|
||||
raw_character_position_--;
|
||||
} while (raw_character_position_ > target_position);
|
||||
return;
|
||||
}
|
||||
// Spool forwards in the utf8 buffer.
|
||||
while (raw_character_position_ < target_position) {
|
||||
if (raw_data_pos_ == raw_data_length_) return;
|
||||
Utf8CharacterForward(raw_data_, &raw_data_pos_);
|
||||
raw_character_position_++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ExternalTwoByteStringUC16CharacterStream
|
||||
|
||||
ExternalTwoByteStringUC16CharacterStream::
|
||||
~ExternalTwoByteStringUC16CharacterStream() { }
|
||||
|
||||
|
||||
ExternalTwoByteStringUC16CharacterStream
|
||||
::ExternalTwoByteStringUC16CharacterStream(
|
||||
Handle<ExternalTwoByteString> data,
|
||||
int start_position,
|
||||
int end_position)
|
||||
: UC16CharacterStream(),
|
||||
source_(data),
|
||||
raw_data_(data->GetTwoByteData(start_position)) {
|
||||
buffer_cursor_ = raw_data_,
|
||||
buffer_end_ = raw_data_ + (end_position - start_position);
|
||||
pos_ = start_position;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Scanner::LiteralScope
|
||||
|
||||
Scanner::LiteralScope::LiteralScope(Scanner* self)
|
||||
: scanner_(self), complete_(false) {
|
||||
self->StartLiteral();
|
||||
}
|
||||
|
||||
|
||||
Scanner::LiteralScope::~LiteralScope() {
|
||||
if (!complete_) scanner_->DropLiteral();
|
||||
}
|
||||
|
||||
|
||||
void Scanner::LiteralScope::Complete() {
|
||||
scanner_->TerminateLiteral();
|
||||
complete_ = true;
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
129
deps/v8/src/scanner-character-streams.h
vendored
Normal file
129
deps/v8/src/scanner-character-streams.h
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2011 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_SCANNER_CHARACTER_STREAMS_H_
|
||||
#define V8_SCANNER_CHARACTER_STREAMS_H_
|
||||
|
||||
#include "scanner.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// A buffered character stream based on a random access character
|
||||
// source (ReadBlock can be called with pos_ pointing to any position,
|
||||
// even positions before the current).
|
||||
class BufferedUC16CharacterStream: public UC16CharacterStream {
|
||||
public:
|
||||
BufferedUC16CharacterStream();
|
||||
virtual ~BufferedUC16CharacterStream();
|
||||
|
||||
virtual void PushBack(uc32 character);
|
||||
|
||||
protected:
|
||||
static const unsigned kBufferSize = 512;
|
||||
static const unsigned kPushBackStepSize = 16;
|
||||
|
||||
virtual unsigned SlowSeekForward(unsigned delta);
|
||||
virtual bool ReadBlock();
|
||||
virtual void SlowPushBack(uc16 character);
|
||||
|
||||
virtual unsigned BufferSeekForward(unsigned delta) = 0;
|
||||
virtual unsigned FillBuffer(unsigned position, unsigned length) = 0;
|
||||
|
||||
const uc16* pushback_limit_;
|
||||
uc16 buffer_[kBufferSize];
|
||||
};
|
||||
|
||||
|
||||
// Generic string stream.
|
||||
class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
|
||||
public:
|
||||
GenericStringUC16CharacterStream(Handle<String> data,
|
||||
unsigned start_position,
|
||||
unsigned end_position);
|
||||
virtual ~GenericStringUC16CharacterStream();
|
||||
|
||||
protected:
|
||||
virtual unsigned BufferSeekForward(unsigned delta);
|
||||
virtual unsigned FillBuffer(unsigned position, unsigned length);
|
||||
|
||||
Handle<String> string_;
|
||||
unsigned start_position_;
|
||||
unsigned length_;
|
||||
};
|
||||
|
||||
|
||||
// UC16 stream based on a literal UTF-8 string.
|
||||
class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
|
||||
public:
|
||||
Utf8ToUC16CharacterStream(const byte* data, unsigned length);
|
||||
virtual ~Utf8ToUC16CharacterStream();
|
||||
|
||||
protected:
|
||||
virtual unsigned BufferSeekForward(unsigned delta);
|
||||
virtual unsigned FillBuffer(unsigned char_position, unsigned length);
|
||||
void SetRawPosition(unsigned char_position);
|
||||
|
||||
const byte* raw_data_;
|
||||
unsigned raw_data_length_; // Measured in bytes, not characters.
|
||||
unsigned raw_data_pos_;
|
||||
// The character position of the character at raw_data[raw_data_pos_].
|
||||
// Not necessarily the same as pos_.
|
||||
unsigned raw_character_position_;
|
||||
};
|
||||
|
||||
|
||||
// UTF16 buffer to read characters from an external string.
|
||||
class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
|
||||
public:
|
||||
ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
|
||||
int start_position,
|
||||
int end_position);
|
||||
virtual ~ExternalTwoByteStringUC16CharacterStream();
|
||||
|
||||
virtual void PushBack(uc32 character) {
|
||||
ASSERT(buffer_cursor_ > raw_data_);
|
||||
buffer_cursor_--;
|
||||
pos_--;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual unsigned SlowSeekForward(unsigned delta) {
|
||||
// Fast case always handles seeking.
|
||||
return 0;
|
||||
}
|
||||
virtual bool ReadBlock() {
|
||||
// Entire string is read at start.
|
||||
return false;
|
||||
}
|
||||
Handle<ExternalTwoByteString> source_;
|
||||
const uc16* raw_data_; // Pointer to the actual array of characters.
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_SCANNER_CHARACTER_STREAMS_H_
|
||||
1266
deps/v8/src/scanner.cc
vendored
1266
deps/v8/src/scanner.cc
vendored
File diff suppressed because it is too large
Load Diff
563
deps/v8/src/scanner.h
vendored
563
deps/v8/src/scanner.h
vendored
@@ -25,103 +25,538 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Features shared by parsing and pre-parsing scanners.
|
||||
|
||||
#ifndef V8_SCANNER_H_
|
||||
#define V8_SCANNER_H_
|
||||
|
||||
#include "scanner-base.h"
|
||||
#include "allocation.h"
|
||||
#include "char-predicates.h"
|
||||
#include "checks.h"
|
||||
#include "globals.h"
|
||||
#include "token.h"
|
||||
#include "unicode-inl.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// A buffered character stream based on a random access character
|
||||
// source (ReadBlock can be called with pos_ pointing to any position,
|
||||
// even positions before the current).
|
||||
class BufferedUC16CharacterStream: public UC16CharacterStream {
|
||||
public:
|
||||
BufferedUC16CharacterStream();
|
||||
virtual ~BufferedUC16CharacterStream();
|
||||
// Returns the value (0 .. 15) of a hexadecimal character c.
|
||||
// If c is not a legal hexadecimal character, returns a value < 0.
|
||||
inline int HexValue(uc32 c) {
|
||||
c -= '0';
|
||||
if (static_cast<unsigned>(c) <= 9) return c;
|
||||
c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
|
||||
if (static_cast<unsigned>(c) <= 5) return c + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual void PushBack(uc32 character);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Buffered stream of characters, using an internal UC16 buffer.
|
||||
|
||||
class UC16CharacterStream {
|
||||
public:
|
||||
UC16CharacterStream() : pos_(0) { }
|
||||
virtual ~UC16CharacterStream() { }
|
||||
|
||||
// Returns and advances past the next UC16 character in the input
|
||||
// stream. If there are no more characters, it returns a negative
|
||||
// value.
|
||||
inline uc32 Advance() {
|
||||
if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
|
||||
pos_++;
|
||||
return static_cast<uc32>(*(buffer_cursor_++));
|
||||
}
|
||||
// Note: currently the following increment is necessary to avoid a
|
||||
// parser problem! The scanner treats the final kEndOfInput as
|
||||
// a character with a position, and does math relative to that
|
||||
// position.
|
||||
pos_++;
|
||||
|
||||
return kEndOfInput;
|
||||
}
|
||||
|
||||
// Return the current position in the character stream.
|
||||
// Starts at zero.
|
||||
inline unsigned pos() const { return pos_; }
|
||||
|
||||
// Skips forward past the next character_count UC16 characters
|
||||
// in the input, or until the end of input if that comes sooner.
|
||||
// Returns the number of characters actually skipped. If less
|
||||
// than character_count,
|
||||
inline unsigned SeekForward(unsigned character_count) {
|
||||
unsigned buffered_chars =
|
||||
static_cast<unsigned>(buffer_end_ - buffer_cursor_);
|
||||
if (character_count <= buffered_chars) {
|
||||
buffer_cursor_ += character_count;
|
||||
pos_ += character_count;
|
||||
return character_count;
|
||||
}
|
||||
return SlowSeekForward(character_count);
|
||||
}
|
||||
|
||||
// Pushes back the most recently read UC16 character (or negative
|
||||
// value if at end of input), i.e., the value returned by the most recent
|
||||
// call to Advance.
|
||||
// Must not be used right after calling SeekForward.
|
||||
virtual void PushBack(int32_t character) = 0;
|
||||
|
||||
protected:
|
||||
static const unsigned kBufferSize = 512;
|
||||
static const unsigned kPushBackStepSize = 16;
|
||||
static const uc32 kEndOfInput = -1;
|
||||
|
||||
virtual unsigned SlowSeekForward(unsigned delta);
|
||||
virtual bool ReadBlock();
|
||||
virtual void SlowPushBack(uc16 character);
|
||||
// Ensures that the buffer_cursor_ points to the character at
|
||||
// position pos_ of the input, if possible. If the position
|
||||
// is at or after the end of the input, return false. If there
|
||||
// are more characters available, return true.
|
||||
virtual bool ReadBlock() = 0;
|
||||
virtual unsigned SlowSeekForward(unsigned character_count) = 0;
|
||||
|
||||
virtual unsigned BufferSeekForward(unsigned delta) = 0;
|
||||
virtual unsigned FillBuffer(unsigned position, unsigned length) = 0;
|
||||
|
||||
const uc16* pushback_limit_;
|
||||
uc16 buffer_[kBufferSize];
|
||||
const uc16* buffer_cursor_;
|
||||
const uc16* buffer_end_;
|
||||
unsigned pos_;
|
||||
};
|
||||
|
||||
|
||||
// Generic string stream.
|
||||
class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
|
||||
class UnicodeCache {
|
||||
// ---------------------------------------------------------------------
|
||||
// Caching predicates used by scanners.
|
||||
public:
|
||||
GenericStringUC16CharacterStream(Handle<String> data,
|
||||
unsigned start_position,
|
||||
unsigned end_position);
|
||||
virtual ~GenericStringUC16CharacterStream();
|
||||
UnicodeCache() {}
|
||||
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
|
||||
|
||||
protected:
|
||||
virtual unsigned BufferSeekForward(unsigned delta);
|
||||
virtual unsigned FillBuffer(unsigned position, unsigned length);
|
||||
StaticResource<Utf8Decoder>* utf8_decoder() {
|
||||
return &utf8_decoder_;
|
||||
}
|
||||
|
||||
Handle<String> string_;
|
||||
unsigned start_position_;
|
||||
unsigned length_;
|
||||
bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
|
||||
bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
|
||||
bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
|
||||
bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
|
||||
|
||||
private:
|
||||
|
||||
unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
|
||||
unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
|
||||
unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
|
||||
unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
|
||||
StaticResource<Utf8Decoder> utf8_decoder_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(UnicodeCache);
|
||||
};
|
||||
|
||||
|
||||
// UC16 stream based on a literal UTF-8 string.
|
||||
class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
|
||||
// ----------------------------------------------------------------------------
|
||||
// LiteralBuffer - Collector of chars of literals.
|
||||
|
||||
class LiteralBuffer {
|
||||
public:
|
||||
Utf8ToUC16CharacterStream(const byte* data, unsigned length);
|
||||
virtual ~Utf8ToUC16CharacterStream();
|
||||
LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { }
|
||||
|
||||
protected:
|
||||
virtual unsigned BufferSeekForward(unsigned delta);
|
||||
virtual unsigned FillBuffer(unsigned char_position, unsigned length);
|
||||
void SetRawPosition(unsigned char_position);
|
||||
~LiteralBuffer() {
|
||||
if (backing_store_.length() > 0) {
|
||||
backing_store_.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
const byte* raw_data_;
|
||||
unsigned raw_data_length_; // Measured in bytes, not characters.
|
||||
unsigned raw_data_pos_;
|
||||
// The character position of the character at raw_data[raw_data_pos_].
|
||||
// Not necessarily the same as pos_.
|
||||
unsigned raw_character_position_;
|
||||
inline void AddChar(uc16 character) {
|
||||
if (position_ >= backing_store_.length()) ExpandBuffer();
|
||||
if (is_ascii_) {
|
||||
if (character < kMaxAsciiCharCodeU) {
|
||||
backing_store_[position_] = static_cast<byte>(character);
|
||||
position_ += kASCIISize;
|
||||
return;
|
||||
}
|
||||
ConvertToUC16();
|
||||
}
|
||||
*reinterpret_cast<uc16*>(&backing_store_[position_]) = character;
|
||||
position_ += kUC16Size;
|
||||
}
|
||||
|
||||
bool is_ascii() { return is_ascii_; }
|
||||
|
||||
Vector<const uc16> uc16_literal() {
|
||||
ASSERT(!is_ascii_);
|
||||
ASSERT((position_ & 0x1) == 0);
|
||||
return Vector<const uc16>(
|
||||
reinterpret_cast<const uc16*>(backing_store_.start()),
|
||||
position_ >> 1);
|
||||
}
|
||||
|
||||
Vector<const char> ascii_literal() {
|
||||
ASSERT(is_ascii_);
|
||||
return Vector<const char>(
|
||||
reinterpret_cast<const char*>(backing_store_.start()),
|
||||
position_);
|
||||
}
|
||||
|
||||
int length() {
|
||||
return is_ascii_ ? position_ : (position_ >> 1);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
position_ = 0;
|
||||
is_ascii_ = true;
|
||||
}
|
||||
private:
|
||||
static const int kInitialCapacity = 16;
|
||||
static const int kGrowthFactory = 4;
|
||||
static const int kMinConversionSlack = 256;
|
||||
static const int kMaxGrowth = 1 * MB;
|
||||
inline int NewCapacity(int min_capacity) {
|
||||
int capacity = Max(min_capacity, backing_store_.length());
|
||||
int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
|
||||
return new_capacity;
|
||||
}
|
||||
|
||||
void ExpandBuffer() {
|
||||
Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
|
||||
memcpy(new_store.start(), backing_store_.start(), position_);
|
||||
backing_store_.Dispose();
|
||||
backing_store_ = new_store;
|
||||
}
|
||||
|
||||
void ConvertToUC16() {
|
||||
ASSERT(is_ascii_);
|
||||
Vector<byte> new_store;
|
||||
int new_content_size = position_ * kUC16Size;
|
||||
if (new_content_size >= backing_store_.length()) {
|
||||
// Ensure room for all currently read characters as UC16 as well
|
||||
// as the character about to be stored.
|
||||
new_store = Vector<byte>::New(NewCapacity(new_content_size));
|
||||
} else {
|
||||
new_store = backing_store_;
|
||||
}
|
||||
char* src = reinterpret_cast<char*>(backing_store_.start());
|
||||
uc16* dst = reinterpret_cast<uc16*>(new_store.start());
|
||||
for (int i = position_ - 1; i >= 0; i--) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
if (new_store.start() != backing_store_.start()) {
|
||||
backing_store_.Dispose();
|
||||
backing_store_ = new_store;
|
||||
}
|
||||
position_ = new_content_size;
|
||||
is_ascii_ = false;
|
||||
}
|
||||
|
||||
bool is_ascii_;
|
||||
int position_;
|
||||
Vector<byte> backing_store_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
|
||||
};
|
||||
|
||||
|
||||
// UTF16 buffer to read characters from an external string.
|
||||
class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
|
||||
public:
|
||||
ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
|
||||
int start_position,
|
||||
int end_position);
|
||||
virtual ~ExternalTwoByteStringUC16CharacterStream();
|
||||
// ----------------------------------------------------------------------------
|
||||
// Scanner base-class.
|
||||
|
||||
virtual void PushBack(uc32 character) {
|
||||
ASSERT(buffer_cursor_ > raw_data_);
|
||||
buffer_cursor_--;
|
||||
pos_--;
|
||||
// Generic functionality used by both JSON and JavaScript scanners.
|
||||
class Scanner {
|
||||
public:
|
||||
// -1 is outside of the range of any real source code.
|
||||
static const int kNoOctalLocation = -1;
|
||||
|
||||
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
|
||||
|
||||
class LiteralScope {
|
||||
public:
|
||||
explicit LiteralScope(Scanner* self);
|
||||
~LiteralScope();
|
||||
void Complete();
|
||||
|
||||
private:
|
||||
Scanner* scanner_;
|
||||
bool complete_;
|
||||
};
|
||||
|
||||
explicit Scanner(UnicodeCache* scanner_contants);
|
||||
|
||||
// Returns the current token again.
|
||||
Token::Value current_token() { return current_.token; }
|
||||
|
||||
// One token look-ahead (past the token returned by Next()).
|
||||
Token::Value peek() const { return next_.token; }
|
||||
|
||||
struct Location {
|
||||
Location(int b, int e) : beg_pos(b), end_pos(e) { }
|
||||
Location() : beg_pos(0), end_pos(0) { }
|
||||
|
||||
bool IsValid() const {
|
||||
return beg_pos >= 0 && end_pos >= beg_pos;
|
||||
}
|
||||
|
||||
static Location invalid() { return Location(-1, -1); }
|
||||
|
||||
int beg_pos;
|
||||
int end_pos;
|
||||
};
|
||||
|
||||
// Returns the location information for the current token
|
||||
// (the token returned by Next()).
|
||||
Location location() const { return current_.location; }
|
||||
Location peek_location() const { return next_.location; }
|
||||
|
||||
// Returns the literal string, if any, for the current token (the
|
||||
// token returned by Next()). The string is 0-terminated and in
|
||||
// UTF-8 format; they may contain 0-characters. Literal strings are
|
||||
// collected for identifiers, strings, and numbers.
|
||||
// These functions only give the correct result if the literal
|
||||
// was scanned between calls to StartLiteral() and TerminateLiteral().
|
||||
bool is_literal_ascii() {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->is_ascii();
|
||||
}
|
||||
Vector<const char> literal_ascii_string() {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->ascii_literal();
|
||||
}
|
||||
Vector<const uc16> literal_uc16_string() {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->uc16_literal();
|
||||
}
|
||||
int literal_length() const {
|
||||
ASSERT_NOT_NULL(current_.literal_chars);
|
||||
return current_.literal_chars->length();
|
||||
}
|
||||
|
||||
bool literal_contains_escapes() const {
|
||||
Location location = current_.location;
|
||||
int source_length = (location.end_pos - location.beg_pos);
|
||||
if (current_.token == Token::STRING) {
|
||||
// Subtract delimiters.
|
||||
source_length -= 2;
|
||||
}
|
||||
return current_.literal_chars->length() != source_length;
|
||||
}
|
||||
|
||||
// Returns the literal string for the next token (the token that
|
||||
// would be returned if Next() were called).
|
||||
bool is_next_literal_ascii() {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->is_ascii();
|
||||
}
|
||||
Vector<const char> next_literal_ascii_string() {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->ascii_literal();
|
||||
}
|
||||
Vector<const uc16> next_literal_uc16_string() {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->uc16_literal();
|
||||
}
|
||||
int next_literal_length() const {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
return next_.literal_chars->length();
|
||||
}
|
||||
|
||||
UnicodeCache* unicode_cache() { return unicode_cache_; }
|
||||
|
||||
static const int kCharacterLookaheadBufferSize = 1;
|
||||
|
||||
protected:
|
||||
virtual unsigned SlowSeekForward(unsigned delta) {
|
||||
// Fast case always handles seeking.
|
||||
return 0;
|
||||
// The current and look-ahead token.
|
||||
struct TokenDesc {
|
||||
Token::Value token;
|
||||
Location location;
|
||||
LiteralBuffer* literal_chars;
|
||||
};
|
||||
|
||||
// Call this after setting source_ to the input.
|
||||
void Init() {
|
||||
// Set c0_ (one character ahead)
|
||||
STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
|
||||
Advance();
|
||||
// Initialize current_ to not refer to a literal.
|
||||
current_.literal_chars = NULL;
|
||||
}
|
||||
virtual bool ReadBlock() {
|
||||
// Entire string is read at start.
|
||||
return false;
|
||||
|
||||
// Literal buffer support
|
||||
inline void StartLiteral() {
|
||||
LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ?
|
||||
&literal_buffer2_ : &literal_buffer1_;
|
||||
free_buffer->Reset();
|
||||
next_.literal_chars = free_buffer;
|
||||
}
|
||||
Handle<ExternalTwoByteString> source_;
|
||||
const uc16* raw_data_; // Pointer to the actual array of characters.
|
||||
|
||||
inline void AddLiteralChar(uc32 c) {
|
||||
ASSERT_NOT_NULL(next_.literal_chars);
|
||||
next_.literal_chars->AddChar(c);
|
||||
}
|
||||
|
||||
// Complete scanning of a literal.
|
||||
inline void TerminateLiteral() {
|
||||
// Does nothing in the current implementation.
|
||||
}
|
||||
|
||||
// Stops scanning of a literal and drop the collected characters,
|
||||
// e.g., due to an encountered error.
|
||||
inline void DropLiteral() {
|
||||
next_.literal_chars = NULL;
|
||||
}
|
||||
|
||||
inline void AddLiteralCharAdvance() {
|
||||
AddLiteralChar(c0_);
|
||||
Advance();
|
||||
}
|
||||
|
||||
// Low-level scanning support.
|
||||
void Advance() { c0_ = source_->Advance(); }
|
||||
void PushBack(uc32 ch) {
|
||||
source_->PushBack(c0_);
|
||||
c0_ = ch;
|
||||
}
|
||||
|
||||
inline Token::Value Select(Token::Value tok) {
|
||||
Advance();
|
||||
return tok;
|
||||
}
|
||||
|
||||
inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
|
||||
Advance();
|
||||
if (c0_ == next) {
|
||||
Advance();
|
||||
return then;
|
||||
} else {
|
||||
return else_;
|
||||
}
|
||||
}
|
||||
|
||||
uc32 ScanHexNumber(int expected_length);
|
||||
|
||||
// Return the current source position.
|
||||
int source_pos() {
|
||||
return source_->pos() - kCharacterLookaheadBufferSize;
|
||||
}
|
||||
|
||||
UnicodeCache* unicode_cache_;
|
||||
|
||||
// Buffers collecting literal strings, numbers, etc.
|
||||
LiteralBuffer literal_buffer1_;
|
||||
LiteralBuffer literal_buffer2_;
|
||||
|
||||
TokenDesc current_; // desc for current token (as returned by Next())
|
||||
TokenDesc next_; // desc for next token (one token look-ahead)
|
||||
|
||||
// Input stream. Must be initialized to an UC16CharacterStream.
|
||||
UC16CharacterStream* source_;
|
||||
|
||||
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
|
||||
uc32 c0_;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// JavaScriptScanner - base logic for JavaScript scanning.
|
||||
|
||||
class JavaScriptScanner : public Scanner {
|
||||
public:
|
||||
// A LiteralScope that disables recording of some types of JavaScript
|
||||
// literals. If the scanner is configured to not record the specific
|
||||
// type of literal, the scope will not call StartLiteral.
|
||||
class LiteralScope {
|
||||
public:
|
||||
explicit LiteralScope(JavaScriptScanner* self)
|
||||
: scanner_(self), complete_(false) {
|
||||
scanner_->StartLiteral();
|
||||
}
|
||||
~LiteralScope() {
|
||||
if (!complete_) scanner_->DropLiteral();
|
||||
}
|
||||
void Complete() {
|
||||
scanner_->TerminateLiteral();
|
||||
complete_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
JavaScriptScanner* scanner_;
|
||||
bool complete_;
|
||||
};
|
||||
|
||||
explicit JavaScriptScanner(UnicodeCache* scanner_contants);
|
||||
|
||||
void Initialize(UC16CharacterStream* source);
|
||||
|
||||
// Returns the next token.
|
||||
Token::Value Next();
|
||||
|
||||
// Returns true if there was a line terminator before the peek'ed token,
|
||||
// possibly inside a multi-line comment.
|
||||
bool HasAnyLineTerminatorBeforeNext() const {
|
||||
return has_line_terminator_before_next_ ||
|
||||
has_multiline_comment_before_next_;
|
||||
}
|
||||
|
||||
// Scans the input as a regular expression pattern, previous
|
||||
// character(s) must be /(=). Returns true if a pattern is scanned.
|
||||
bool ScanRegExpPattern(bool seen_equal);
|
||||
// Returns true if regexp flags are scanned (always since flags can
|
||||
// be empty).
|
||||
bool ScanRegExpFlags();
|
||||
|
||||
// Tells whether the buffer contains an identifier (no escapes).
|
||||
// Used for checking if a property name is an identifier.
|
||||
static bool IsIdentifier(unibrow::CharacterStream* buffer);
|
||||
|
||||
// Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
|
||||
uc32 ScanOctalEscape(uc32 c, int length);
|
||||
|
||||
// Returns the location of the last seen octal literal
|
||||
Location octal_position() const { return octal_pos_; }
|
||||
void clear_octal_position() { octal_pos_ = Location::invalid(); }
|
||||
|
||||
// Seek forward to the given position. This operation does not
|
||||
// work in general, for instance when there are pushed back
|
||||
// characters, but works for seeking forward until simple delimiter
|
||||
// tokens, which is what it is used for.
|
||||
void SeekForward(int pos);
|
||||
|
||||
bool HarmonyBlockScoping() const {
|
||||
return harmony_block_scoping_;
|
||||
}
|
||||
void SetHarmonyBlockScoping(bool block_scoping) {
|
||||
harmony_block_scoping_ = block_scoping;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
bool SkipWhiteSpace();
|
||||
Token::Value SkipSingleLineComment();
|
||||
Token::Value SkipMultiLineComment();
|
||||
|
||||
// Scans a single JavaScript token.
|
||||
void Scan();
|
||||
|
||||
void ScanDecimalDigits();
|
||||
Token::Value ScanNumber(bool seen_period);
|
||||
Token::Value ScanIdentifierOrKeyword();
|
||||
Token::Value ScanIdentifierSuffix(LiteralScope* literal);
|
||||
|
||||
void ScanEscape();
|
||||
Token::Value ScanString();
|
||||
|
||||
// Scans a possible HTML comment -- begins with '<!'.
|
||||
Token::Value ScanHtmlComment();
|
||||
|
||||
// Decodes a unicode escape-sequence which is part of an identifier.
|
||||
// If the escape sequence cannot be decoded the result is kBadChar.
|
||||
uc32 ScanIdentifierUnicodeEscape();
|
||||
// Recognizes a uniocde escape-sequence and adds its characters,
|
||||
// uninterpreted, to the current literal. Used for parsing RegExp
|
||||
// flags.
|
||||
bool ScanLiteralUnicodeEscape();
|
||||
|
||||
// Start position of the octal literal last scanned.
|
||||
Location octal_pos_;
|
||||
|
||||
// Whether there is a line terminator whitespace character after
|
||||
// the current token, and before the next. Does not count newlines
|
||||
// inside multiline comments.
|
||||
bool has_line_terminator_before_next_;
|
||||
// Whether there is a multi-line comment that contains a
|
||||
// line-terminator after the current token, and before the next.
|
||||
bool has_multiline_comment_before_next_;
|
||||
// Whether we scan 'let' as a keyword for harmony block scoped
|
||||
// let bindings.
|
||||
bool harmony_block_scoping_;
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
43
deps/v8/src/smart-pointer.h
vendored
43
deps/v8/src/smart-pointer.h
vendored
@@ -37,35 +37,31 @@ namespace internal {
|
||||
template<typename T>
|
||||
class SmartPointer {
|
||||
public:
|
||||
// Default constructor. Constructs an empty scoped pointer.
|
||||
inline SmartPointer() : p_(NULL) {}
|
||||
|
||||
// Default constructor. Construct an empty scoped pointer.
|
||||
inline SmartPointer() : p(NULL) {}
|
||||
|
||||
|
||||
// Construct a scoped pointer from a plain one.
|
||||
explicit inline SmartPointer(T* pointer) : p(pointer) {}
|
||||
|
||||
// Constructs a scoped pointer from a plain one.
|
||||
explicit inline SmartPointer(T* ptr) : p_(ptr) {}
|
||||
|
||||
// Copy constructor removes the pointer from the original to avoid double
|
||||
// freeing.
|
||||
inline SmartPointer(const SmartPointer<T>& rhs) : p(rhs.p) {
|
||||
const_cast<SmartPointer<T>&>(rhs).p = NULL;
|
||||
inline SmartPointer(const SmartPointer<T>& rhs) : p_(rhs.p_) {
|
||||
const_cast<SmartPointer<T>&>(rhs).p_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
// When the destructor of the scoped pointer is executed the plain pointer
|
||||
// is deleted using DeleteArray. This implies that you must allocate with
|
||||
// NewArray.
|
||||
inline ~SmartPointer() { if (p) DeleteArray(p); }
|
||||
inline ~SmartPointer() { if (p_) DeleteArray(p_); }
|
||||
|
||||
inline T* operator->() const { return p_; }
|
||||
|
||||
// You can get the underlying pointer out with the * operator.
|
||||
inline T* operator*() { return p; }
|
||||
|
||||
inline T* operator*() { return p_; }
|
||||
|
||||
// You can use [n] to index as if it was a plain pointer
|
||||
inline T& operator[](size_t i) {
|
||||
return p[i];
|
||||
return p_[i];
|
||||
}
|
||||
|
||||
// We don't have implicit conversion to a T* since that hinders migration:
|
||||
@@ -77,31 +73,26 @@ class SmartPointer {
|
||||
// deleted then call Detach(). Afterwards, the smart pointer is empty
|
||||
// (NULL).
|
||||
inline T* Detach() {
|
||||
T* temp = p;
|
||||
p = NULL;
|
||||
T* temp = p_;
|
||||
p_ = NULL;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
// Assignment requires an empty (NULL) SmartPointer as the receiver. Like
|
||||
// the copy constructor it removes the pointer in the original to avoid
|
||||
// double freeing.
|
||||
inline SmartPointer& operator=(const SmartPointer<T>& rhs) {
|
||||
ASSERT(is_empty());
|
||||
T* tmp = rhs.p; // swap to handle self-assignment
|
||||
const_cast<SmartPointer<T>&>(rhs).p = NULL;
|
||||
p = tmp;
|
||||
T* tmp = rhs.p_; // swap to handle self-assignment
|
||||
const_cast<SmartPointer<T>&>(rhs).p_ = NULL;
|
||||
p_ = tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline bool is_empty() {
|
||||
return p == NULL;
|
||||
}
|
||||
|
||||
inline bool is_empty() { return p_ == NULL; }
|
||||
|
||||
private:
|
||||
T* p;
|
||||
T* p_;
|
||||
};
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
7
deps/v8/src/strtod.cc
vendored
7
deps/v8/src/strtod.cc
vendored
@@ -26,14 +26,11 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <limits>
|
||||
|
||||
#ifndef V8_INFINITY
|
||||
#define V8_INFINITY std::numeric_limits<double>::infinity()
|
||||
#endif
|
||||
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "strtod.h"
|
||||
#include "bignum.h"
|
||||
#include "cached-powers.h"
|
||||
|
||||
78
deps/v8/src/utils.h
vendored
78
deps/v8/src/utils.h
vendored
@@ -497,9 +497,6 @@ class Collector {
|
||||
public:
|
||||
explicit Collector(int initial_capacity = kMinCapacity)
|
||||
: index_(0), size_(0) {
|
||||
if (initial_capacity < kMinCapacity) {
|
||||
initial_capacity = kMinCapacity;
|
||||
}
|
||||
current_chunk_ = Vector<T>::New(initial_capacity);
|
||||
}
|
||||
|
||||
@@ -601,25 +598,23 @@ class Collector {
|
||||
// Creates a new current chunk, and stores the old chunk in the chunks_ list.
|
||||
void Grow(int min_capacity) {
|
||||
ASSERT(growth_factor > 1);
|
||||
int growth = current_chunk_.length() * (growth_factor - 1);
|
||||
if (growth > max_growth) {
|
||||
growth = max_growth;
|
||||
}
|
||||
int new_capacity = current_chunk_.length() + growth;
|
||||
if (new_capacity < min_capacity) {
|
||||
new_capacity = min_capacity + growth;
|
||||
}
|
||||
Vector<T> new_chunk = Vector<T>::New(new_capacity);
|
||||
int new_index = PrepareGrow(new_chunk);
|
||||
if (index_ > 0) {
|
||||
chunks_.Add(current_chunk_.SubVector(0, index_));
|
||||
int new_capacity;
|
||||
int current_length = current_chunk_.length();
|
||||
if (current_length < kMinCapacity) {
|
||||
// The collector started out as empty.
|
||||
new_capacity = min_capacity * growth_factor;
|
||||
if (new_capacity < kMinCapacity) new_capacity = kMinCapacity;
|
||||
} else {
|
||||
// Can happen if the call to PrepareGrow moves everything into
|
||||
// the new chunk.
|
||||
current_chunk_.Dispose();
|
||||
int growth = current_length * (growth_factor - 1);
|
||||
if (growth > max_growth) {
|
||||
growth = max_growth;
|
||||
}
|
||||
new_capacity = current_length + growth;
|
||||
if (new_capacity < min_capacity) {
|
||||
new_capacity = min_capacity + growth;
|
||||
}
|
||||
}
|
||||
current_chunk_ = new_chunk;
|
||||
index_ = new_index;
|
||||
NewChunk(new_capacity);
|
||||
ASSERT(index_ + min_capacity <= current_chunk_.length());
|
||||
}
|
||||
|
||||
@@ -627,8 +622,15 @@ class Collector {
|
||||
// some of the current data into the new chunk. The function may update
|
||||
// the current index_ value to represent data no longer in the current chunk.
|
||||
// Returns the initial index of the new chunk (after copied data).
|
||||
virtual int PrepareGrow(Vector<T> new_chunk) {
|
||||
return 0;
|
||||
virtual void NewChunk(int new_capacity) {
|
||||
Vector<T> new_chunk = Vector<T>::New(new_capacity);
|
||||
if (index_ > 0) {
|
||||
chunks_.Add(current_chunk_.SubVector(0, index_));
|
||||
} else {
|
||||
current_chunk_.Dispose();
|
||||
}
|
||||
current_chunk_ = new_chunk;
|
||||
index_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -683,20 +685,26 @@ class SequenceCollector : public Collector<T, growth_factor, max_growth> {
|
||||
int sequence_start_;
|
||||
|
||||
// Move the currently active sequence to the new chunk.
|
||||
virtual int PrepareGrow(Vector<T> new_chunk) {
|
||||
if (sequence_start_ != kNoSequence) {
|
||||
int sequence_length = this->index_ - sequence_start_;
|
||||
// The new chunk is always larger than the current chunk, so there
|
||||
// is room for the copy.
|
||||
ASSERT(sequence_length < new_chunk.length());
|
||||
for (int i = 0; i < sequence_length; i++) {
|
||||
new_chunk[i] = this->current_chunk_[sequence_start_ + i];
|
||||
}
|
||||
this->index_ = sequence_start_;
|
||||
sequence_start_ = 0;
|
||||
return sequence_length;
|
||||
virtual void NewChunk(int new_capacity) {
|
||||
if (sequence_start_ == kNoSequence) {
|
||||
// Fall back on default behavior if no sequence has been started.
|
||||
this->Collector<T, growth_factor, max_growth>::NewChunk(new_capacity);
|
||||
return;
|
||||
}
|
||||
return 0;
|
||||
int sequence_length = this->index_ - sequence_start_;
|
||||
Vector<T> new_chunk = Vector<T>::New(sequence_length + new_capacity);
|
||||
ASSERT(sequence_length < new_chunk.length());
|
||||
for (int i = 0; i < sequence_length; i++) {
|
||||
new_chunk[i] = this->current_chunk_[sequence_start_ + i];
|
||||
}
|
||||
if (sequence_start_ > 0) {
|
||||
this->chunks_.Add(this->current_chunk_.SubVector(0, sequence_start_));
|
||||
} else {
|
||||
this->current_chunk_.Dispose();
|
||||
}
|
||||
this->current_chunk_ = new_chunk;
|
||||
this->index_ = sequence_length;
|
||||
sequence_start_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
1
deps/v8/src/v8conversions.cc
vendored
1
deps/v8/src/v8conversions.cc
vendored
@@ -34,7 +34,6 @@
|
||||
#include "v8conversions.h"
|
||||
#include "dtoa.h"
|
||||
#include "factory.h"
|
||||
#include "scanner-base.h"
|
||||
#include "strtod.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
2
deps/v8/src/version.cc
vendored
2
deps/v8/src/version.cc
vendored
@@ -34,7 +34,7 @@
|
||||
// cannot be changed without changing the SCons build script.
|
||||
#define MAJOR_VERSION 3
|
||||
#define MINOR_VERSION 6
|
||||
#define BUILD_NUMBER 1
|
||||
#define BUILD_NUMBER 2
|
||||
#define PATCH_LEVEL 0
|
||||
// Use 1 for candidates and 0 otherwise.
|
||||
// (Boolean macro values are not supported by all preprocessors.)
|
||||
|
||||
106
deps/v8/src/win32-math.cc
vendored
Normal file
106
deps/v8/src/win32-math.cc
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
|
||||
// refer to The Open Group Base Specification for specification of the correct
|
||||
// semantics for these functions.
|
||||
// (http://www.opengroup.org/onlinepubs/000095399/)
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#undef V8_WIN32_LEAN_AND_MEAN
|
||||
#define V8_WIN32_HEADERS_FULL
|
||||
#include "win32-headers.h"
|
||||
#include <limits.h> // Required for INT_MAX etc.
|
||||
#include <math.h>
|
||||
#include <float.h> // Required for DBL_MAX and on Win32 for finite()
|
||||
#include "win32-math.h"
|
||||
|
||||
#include "checks.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
// Test for finite value - usually defined in math.h
|
||||
int isfinite(double x) {
|
||||
return _finite(x);
|
||||
}
|
||||
|
||||
} // namespace v8
|
||||
|
||||
|
||||
// Test for a NaN (not a number) value - usually defined in math.h
|
||||
int isnan(double x) {
|
||||
return _isnan(x);
|
||||
}
|
||||
|
||||
|
||||
// Test for infinity - usually defined in math.h
|
||||
int isinf(double x) {
|
||||
return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0;
|
||||
}
|
||||
|
||||
|
||||
// Test if x is less than y and both nominal - usually defined in math.h
|
||||
int isless(double x, double y) {
|
||||
return isnan(x) || isnan(y) ? 0 : x < y;
|
||||
}
|
||||
|
||||
|
||||
// Test if x is greater than y and both nominal - usually defined in math.h
|
||||
int isgreater(double x, double y) {
|
||||
return isnan(x) || isnan(y) ? 0 : x > y;
|
||||
}
|
||||
|
||||
|
||||
// Classify floating point number - usually defined in math.h
|
||||
int fpclassify(double x) {
|
||||
// Use the MS-specific _fpclass() for classification.
|
||||
int flags = _fpclass(x);
|
||||
|
||||
// Determine class. We cannot use a switch statement because
|
||||
// the _FPCLASS_ constants are defined as flags.
|
||||
if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL;
|
||||
if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO;
|
||||
if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL;
|
||||
if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE;
|
||||
|
||||
// All cases should be covered by the code above.
|
||||
ASSERT(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN));
|
||||
return FP_NAN;
|
||||
}
|
||||
|
||||
|
||||
// Test sign - usually defined in math.h
|
||||
int signbit(double x) {
|
||||
// We need to take care of the special case of both positive
|
||||
// and negative versions of zero.
|
||||
if (x == 0)
|
||||
return _fpclass(x) & _FPCLASS_NZ;
|
||||
else
|
||||
return x < 0;
|
||||
}
|
||||
|
||||
#endif // _MSC_VER
|
||||
61
deps/v8/src/win32-math.h
vendored
Normal file
61
deps/v8/src/win32-math.h
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
|
||||
// refer to The Open Group Base Specification for specification of the correct
|
||||
// semantics for these functions.
|
||||
// (http://www.opengroup.org/onlinepubs/000095399/)
|
||||
|
||||
#ifndef V8_WIN32_MATH_H_
|
||||
#define V8_WIN32_MATH_H_
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#error Wrong environment, expected MSVC.
|
||||
#endif // _MSC_VER
|
||||
|
||||
enum {
|
||||
FP_NAN,
|
||||
FP_INFINITE,
|
||||
FP_ZERO,
|
||||
FP_SUBNORMAL,
|
||||
FP_NORMAL
|
||||
};
|
||||
|
||||
namespace v8 {
|
||||
|
||||
int isfinite(double x);
|
||||
|
||||
} // namespace v8
|
||||
|
||||
int isnan(double x);
|
||||
int isinf(double x);
|
||||
int isless(double x, double y);
|
||||
int isgreater(double x, double y);
|
||||
int fpclassify(double x);
|
||||
int signbit(double x);
|
||||
|
||||
#endif // V8_WIN32_MATH_H_
|
||||
14
deps/v8/test/cctest/test-parsing.cc
vendored
14
deps/v8/test/cctest/test-parsing.cc
vendored
@@ -31,14 +31,14 @@
|
||||
|
||||
#include "v8.h"
|
||||
|
||||
#include "isolate.h"
|
||||
#include "token.h"
|
||||
#include "scanner.h"
|
||||
#include "parser.h"
|
||||
#include "utils.h"
|
||||
#include "execution.h"
|
||||
#include "preparser.h"
|
||||
#include "cctest.h"
|
||||
#include "execution.h"
|
||||
#include "isolate.h"
|
||||
#include "parser.h"
|
||||
#include "preparser.h"
|
||||
#include "scanner-character-streams.h"
|
||||
#include "token.h"
|
||||
#include "utils.h"
|
||||
|
||||
TEST(ScanKeywords) {
|
||||
struct KeywordToken {
|
||||
|
||||
@@ -37,16 +37,16 @@ TEST(TokenEnumerator) {
|
||||
TokenEnumerator te;
|
||||
CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
|
||||
v8::HandleScope hs;
|
||||
v8::Local<v8::String> token1(v8::String::New("1"));
|
||||
v8::Local<v8::String> token1(v8::String::New("1x"));
|
||||
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
|
||||
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
|
||||
v8::Local<v8::String> token2(v8::String::New("2"));
|
||||
v8::Local<v8::String> token2(v8::String::New("2x"));
|
||||
CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
|
||||
CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
|
||||
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
|
||||
{
|
||||
v8::HandleScope hs;
|
||||
v8::Local<v8::String> token3(v8::String::New("3"));
|
||||
v8::Local<v8::String> token3(v8::String::New("3x"));
|
||||
CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
|
||||
CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
|
||||
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
|
||||
|
||||
12
deps/v8/test/cctest/test-utils.cc
vendored
12
deps/v8/test/cctest/test-utils.cc
vendored
@@ -195,3 +195,15 @@ TEST(SequenceCollector) {
|
||||
}
|
||||
result.Dispose();
|
||||
}
|
||||
|
||||
|
||||
TEST(SequenceCollectorRegression) {
|
||||
SequenceCollector<char> collector(16);
|
||||
collector.StartSequence();
|
||||
collector.Add('0');
|
||||
collector.AddBlock(
|
||||
i::Vector<const char>("12345678901234567890123456789012", 32));
|
||||
i::Vector<char> seq = collector.EndSequence();
|
||||
CHECK_EQ(0, strncmp("0123456789012345678901234567890123",
|
||||
seq.start(), seq.length()));
|
||||
}
|
||||
|
||||
5
deps/v8/test/mjsunit/string-replace.js
vendored
5
deps/v8/test/mjsunit/string-replace.js
vendored
@@ -207,3 +207,8 @@ replaceTest("[ab-aabb-ab-b][az-aazz-az-z]",
|
||||
|
||||
replaceTest("[ab-aabb-ab-b][az-aazz-az-z]",
|
||||
"abaz", /a(.)/g, replacer);
|
||||
|
||||
var str = 'She sells seashells by the seashore.';
|
||||
var re = /sh/g;
|
||||
assertEquals('She sells sea$schells by the sea$schore.',
|
||||
str.replace(re,"$$" + 'sch'))
|
||||
|
||||
90
deps/v8/test/preparser/duplicate-parameter.pyt
vendored
Normal file
90
deps/v8/test/preparser/duplicate-parameter.pyt
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
# Copyright 2011 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.
|
||||
|
||||
# Templatated tests with duplicate parameter names.
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Constants and utility functions
|
||||
|
||||
# A template that performs the same strict-mode test in different
|
||||
# scopes (global scope, function scope, and nested function scope),
|
||||
# and in non-strict mode too.
|
||||
def DuplicateParameterTest(name, source):
|
||||
expectation = "strict_param_dupe"
|
||||
non_selfstrict = {"selfstrict":"", "id":"selfnormal"}
|
||||
|
||||
Template(name, '"use strict";\n' + source)(non_selfstrict, expectation)
|
||||
Template(name + '-infunc',
|
||||
'function foo() {\n "use strict";\n' + source +'\n}\n')(
|
||||
non_selfstrict, expectation)
|
||||
Template(name + '-infunc2',
|
||||
'function foo() {\n "use strict";\n function bar() {\n' +
|
||||
source +'\n }\n}\n')(non_selfstrict, expectation)
|
||||
|
||||
selfstrict = {"selfstrict": "\"use strict\";", "id": "selfstrict"}
|
||||
nestedstrict = {"selfstrict": "function bar(){\"use strict\";}",
|
||||
"id": "nestedstrict"}
|
||||
selfstrictnestedclean = {"selfstrict": """
|
||||
"use strict";
|
||||
function bar(){}
|
||||
""", "id": "selfstrictnestedclean"}
|
||||
selftest = Template(name + '-$id', source)
|
||||
selftest(selfstrict, expectation)
|
||||
selftest(selfstrictnestedclean, expectation)
|
||||
selftest(nestedstrict, None)
|
||||
selftest(non_selfstrict, None)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Test templates
|
||||
|
||||
DuplicateParameterTest("dups", """
|
||||
function foo(a, a) { $selfstrict }
|
||||
""");
|
||||
|
||||
DuplicateParameterTest("dups-apart", """
|
||||
function foo(a, b, c, d, e, f, g, h, i, j, k, l, m, n, a) { $selfstrict }
|
||||
""");
|
||||
|
||||
DuplicateParameterTest("dups-escaped", """
|
||||
function foo(\u0061, b, c, d, e, f, g, h, i, j, k, l, m, n, a) { $selfstrict }
|
||||
""");
|
||||
|
||||
DuplicateParameterTest("triples", """
|
||||
function foo(a, b, c, d, e, f, g, h, a, i, j, k, l, m, n, a) { $selfstrict }
|
||||
""");
|
||||
|
||||
DuplicateParameterTest("escapes", """
|
||||
function foo(a, \u0061) { $selfstrict }
|
||||
""");
|
||||
|
||||
DuplicateParameterTest("long-names", """
|
||||
function foo(arglebargleglopglyfarglebargleglopglyfarglebargleglopglyfa,
|
||||
arglebargleglopglyfarglebargleglopglyfarglebargleglopglyfa) {
|
||||
$selfstrict
|
||||
}
|
||||
""");
|
||||
162
deps/v8/test/preparser/duplicate-property.pyt
vendored
Normal file
162
deps/v8/test/preparser/duplicate-property.pyt
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
# Copyright 2011 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.
|
||||
|
||||
# Tests of duplicate properties in object literals.
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Utility functions to generate a number of tests for each property
|
||||
# name pair.
|
||||
|
||||
def PropertyTest(name, propa, propb, allow_strict = True):
|
||||
replacement = {"id1": propa, "id2": propb, "name": name}
|
||||
|
||||
# Tests same test in both strict and non-strict context.
|
||||
def StrictTest(name, source, replacement, expectation):
|
||||
if (allow_strict):
|
||||
Template("strict-" + name,
|
||||
"\"use strict\";\n" + source)(replacement, expectation)
|
||||
Template(name, source)(replacement, expectation)
|
||||
|
||||
# This one only fails in non-strict context.
|
||||
if (allow_strict):
|
||||
Template("strict-$name-data-data", """
|
||||
"use strict";
|
||||
var o = {$id1: 42, $id2: 42};
|
||||
""")(replacement, "strict_duplicate_property")
|
||||
|
||||
Template("$name-data-data", """
|
||||
var o = {$id1: 42, $id2: 42};
|
||||
""")(replacement, None)
|
||||
|
||||
StrictTest("$name-data-get", """
|
||||
var o = {$id1: 42, get $id2(){}};
|
||||
""", replacement, "accessor_data_property")
|
||||
|
||||
StrictTest("$name-data-set", """
|
||||
var o = {$id1: 42, set $id2(v){}};
|
||||
""", replacement, "accessor_data_property")
|
||||
|
||||
StrictTest("$name-get-data", """
|
||||
var o = {get $id1(){}, $id2: 42};
|
||||
""", replacement, "accessor_data_property")
|
||||
|
||||
StrictTest("$name-set-data", """
|
||||
var o = {set $id1(v){}, $id2: 42};
|
||||
""", replacement, "accessor_data_property")
|
||||
|
||||
StrictTest("$name-get-get", """
|
||||
var o = {get $id1(){}, get $id2(){}};
|
||||
""", replacement, "accessor_get_set")
|
||||
|
||||
StrictTest("$name-set-set", """
|
||||
var o = {set $id1(v){}, set $id2(v){}};
|
||||
""", replacement, "accessor_get_set")
|
||||
|
||||
StrictTest("$name-nested-get", """
|
||||
var o = {get $id1(){}, o: {get $id2(){} } };
|
||||
""", replacement, None)
|
||||
|
||||
StrictTest("$name-nested-set", """
|
||||
var o = {set $id1(){}, o: {set $id2(){} } };
|
||||
""", replacement, None)
|
||||
|
||||
|
||||
def TestBothWays(name, propa, propb, allow_strict = True):
|
||||
PropertyTest(name + "-1", propa, propb, allow_strict)
|
||||
PropertyTest(name + "-2", propb, propa, allow_strict)
|
||||
|
||||
def TestSame(name, prop, allow_strict = True):
|
||||
PropertyTest(name, prop, prop, allow_strict)
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
# Simple identifier property
|
||||
TestSame("a", "a")
|
||||
|
||||
# Get/set identifiers
|
||||
TestSame("get-id", "get")
|
||||
TestSame("set-id", "set")
|
||||
|
||||
# Number properties
|
||||
TestSame("0", "0")
|
||||
TestSame("0.1", "0.1")
|
||||
TestSame("1.0", "1.0")
|
||||
TestSame("42.33", "42.33")
|
||||
TestSame("2^32-2", "4294967294")
|
||||
TestSame("2^32", "4294967296")
|
||||
TestSame("2^53", "9007199254740992")
|
||||
TestSame("Hex20", "0x20")
|
||||
TestSame("exp10", "1e10")
|
||||
TestSame("exp20", "1e20")
|
||||
TestSame("Oct40", "040", False);
|
||||
|
||||
|
||||
# String properties
|
||||
TestSame("str-a", '"a"')
|
||||
TestSame("str-0", '"0"')
|
||||
TestSame("str-42", '"42"')
|
||||
TestSame("str-empty", '""')
|
||||
|
||||
# Keywords
|
||||
TestSame("if", "if")
|
||||
TestSame("case", "case")
|
||||
|
||||
# Future reserved keywords
|
||||
TestSame("public", "public")
|
||||
TestSame("class", "class")
|
||||
|
||||
|
||||
# Test that numbers are converted to string correctly.
|
||||
|
||||
TestBothWays("hex-int", "0x20", "32")
|
||||
TestBothWays("oct-int", "040", "32", False) # Octals disallowed in strict mode.
|
||||
TestBothWays("dec-int", "32.00", "32")
|
||||
TestBothWays("dec-underflow-int",
|
||||
"32.00000000000000000000000000000000000000001", "32")
|
||||
TestBothWays("exp-int", "3.2e1", "32")
|
||||
TestBothWays("exp-int", "3200e-2", "32")
|
||||
TestBothWays("overflow-inf", "1e2000", "Infinity")
|
||||
TestBothWays("overflow-inf-exact", "1.797693134862315808e+308", "Infinity")
|
||||
TestBothWays("non-overflow-inf-exact", "1.797693134862315807e+308",
|
||||
"1.7976931348623157e+308")
|
||||
TestBothWays("underflow-0", "1e-2000", "0")
|
||||
TestBothWays("underflow-0-exact", "2.4703282292062E-324", "0")
|
||||
TestBothWays("non-underflow-0-exact", "2.4703282292063E-324", "5e-324")
|
||||
TestBothWays("precission-loss-high", "9007199254740992", "9007199254740993")
|
||||
TestBothWays("precission-loss-low", "1.9999999999999998", "1.9999999999999997")
|
||||
TestBothWays("non-canonical-literal-int", "1.0", "1")
|
||||
TestBothWays("non-canonical-literal-frac", "1.50", "1.5")
|
||||
TestBothWays("rounding-down", "1.12512512512512452", "1.1251251251251244")
|
||||
TestBothWays("rounding-up", "1.12512512512512453", "1.1251251251251246")
|
||||
|
||||
TestBothWays("hex-int-str", "0x20", '"32"')
|
||||
TestBothWays("dec-int-str", "32.00", '"32"')
|
||||
TestBothWays("exp-int-str", "3.2e1", '"32"')
|
||||
TestBothWays("overflow-inf-str", "1e2000", '"Infinity"')
|
||||
TestBothWays("underflow-0-str", "1e-2000", '"0"')
|
||||
TestBothWays("non-canonical-literal-int-str", "1.0", '"1"')
|
||||
TestBothWays("non-canonical-literal-frac-str", "1.50", '"1.5"')
|
||||
6
deps/v8/test/preparser/testcfg.py
vendored
6
deps/v8/test/preparser/testcfg.py
vendored
@@ -98,7 +98,6 @@ class PreparserTestConfiguration(test.TestConfiguration):
|
||||
def ParsePythonTestTemplates(self, result, filename,
|
||||
executable, current_path, mode):
|
||||
pathname = join(self.root, filename + ".pyt")
|
||||
source = open(pathname).read();
|
||||
def Test(name, source, expectation):
|
||||
throws = None
|
||||
if (expectation is not None):
|
||||
@@ -118,8 +117,7 @@ class PreparserTestConfiguration(test.TestConfiguration):
|
||||
testsource = testsource.replace("$"+key, replacement[key]);
|
||||
Test(testname, testsource, expectation)
|
||||
return MkTest
|
||||
eval(compile(source, pathname, "exec"),
|
||||
{"Test": Test, "Template": Template}, {})
|
||||
execfile(pathname, {"Test": Test, "Template": Template})
|
||||
|
||||
def ListTests(self, current_path, path, mode, variant_flags):
|
||||
executable = 'preparser'
|
||||
@@ -148,7 +146,7 @@ class PreparserTestConfiguration(test.TestConfiguration):
|
||||
filenames.sort()
|
||||
for file in filenames:
|
||||
# Each file as a python source file to be executed in a specially
|
||||
# perparsed environment (defining the Template and Test functions)
|
||||
# created environment (defining the Template and Test functions)
|
||||
self.ParsePythonTestTemplates(result, file,
|
||||
executable, current_path, mode)
|
||||
return result
|
||||
|
||||
61
deps/v8/tools/gyp/v8.gyp
vendored
61
deps/v8/tools/gyp/v8.gyp
vendored
@@ -71,6 +71,13 @@
|
||||
],
|
||||
},
|
||||
}],
|
||||
['soname_version!=""', {
|
||||
# Ideally, we'd like to specify the full filename for the
|
||||
# library and set it to "libv8.so.<(soname_version)",
|
||||
# but currently the best we can do is use 'product_name' and
|
||||
# get "libv8-<(soname_version).so".
|
||||
'product_name': 'v8-<(soname_version)',
|
||||
}],
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -288,11 +295,11 @@
|
||||
'../../src/disasm.h',
|
||||
'../../src/disassembler.cc',
|
||||
'../../src/disassembler.h',
|
||||
'../../src/dtoa.cc',
|
||||
'../../src/dtoa.h',
|
||||
'../../src/diy-fp.cc',
|
||||
'../../src/diy-fp.h',
|
||||
'../../src/double.h',
|
||||
'../../src/dtoa.cc',
|
||||
'../../src/dtoa.h',
|
||||
'../../src/elements.cc',
|
||||
'../../src/elements.h',
|
||||
'../../src/execution.cc',
|
||||
@@ -407,10 +414,10 @@
|
||||
'../../src/runtime-profiler.h',
|
||||
'../../src/safepoint-table.cc',
|
||||
'../../src/safepoint-table.h',
|
||||
'../../src/scanner-base.cc',
|
||||
'../../src/scanner-base.h',
|
||||
'../../src/scanner.cc',
|
||||
'../../src/scanner.h',
|
||||
'../../src/scanner-character-streams.cc',
|
||||
'../../src/scanner-character-streams.h',
|
||||
'../../src/scopeinfo.cc',
|
||||
'../../src/scopeinfo.h',
|
||||
'../../src/scopes.cc',
|
||||
@@ -643,6 +650,8 @@
|
||||
['OS=="win"', {
|
||||
'sources': [
|
||||
'../../src/platform-win32.cc',
|
||||
'../../src/win32-math.cc',
|
||||
'../../src/win32-math.h',
|
||||
],
|
||||
'msvs_disabled_warnings': [4351, 4355, 4800],
|
||||
'link_settings': {
|
||||
@@ -787,19 +796,61 @@
|
||||
'../../src',
|
||||
],
|
||||
'sources': [
|
||||
'../../include/v8-preparser.h',
|
||||
'../../include/v8stdint.h',
|
||||
'../../src/allocation.cc',
|
||||
'../../src/allocation.h',
|
||||
'../../src/bignum.cc',
|
||||
'../../src/bignum.h',
|
||||
'../../src/bignum-dtoa.cc',
|
||||
'../../src/bignum-dtoa.h',
|
||||
'../../src/cached-powers.cc',
|
||||
'../../src/cached-powers.h',
|
||||
'../../src/char-predicates-inl.h',
|
||||
'../../src/char-predicates.h',
|
||||
'../../src/checks.h',
|
||||
'../../src/conversions-inl.h',
|
||||
'../../src/conversions.cc',
|
||||
'../../src/conversions.h',
|
||||
'../../src/diy-fp.cc',
|
||||
'../../src/diy-fp.h',
|
||||
'../../src/double.h',
|
||||
'../../src/dtoa.cc',
|
||||
'../../src/dtoa.h',
|
||||
'../../src/fast-dtoa.cc',
|
||||
'../../src/fast-dtoa.h',
|
||||
'../../src/fixed-dtoa.cc',
|
||||
'../../src/fixed-dtoa.h',
|
||||
'../../src/globals.h',
|
||||
'../../src/hashmap.cc',
|
||||
'../../src/hashmap.h',
|
||||
'../../src/list-inl.h',
|
||||
'../../src/list.h',
|
||||
'../../src/preparse-data-format.h',
|
||||
'../../src/preparse-data.cc',
|
||||
'../../src/preparse-data.h',
|
||||
'../../src/preparser.cc',
|
||||
'../../src/preparser.h',
|
||||
'../../src/preparser-api.cc',
|
||||
'../../src/scanner-base.cc',
|
||||
'../../src/scanner.cc',
|
||||
'../../src/scanner.h',
|
||||
'../../src/strtod.cc',
|
||||
'../../src/strtod.h',
|
||||
'../../src/token.cc',
|
||||
'../../src/token.h',
|
||||
'../../src/unicode-inl.h',
|
||||
'../../src/unicode.cc',
|
||||
'../../src/unicode.h',
|
||||
'../../src/utils-inl.h',
|
||||
'../../src/utils.cc',
|
||||
'../../src/utils.h',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'sources': [
|
||||
'../../src/win32-math.cc',
|
||||
'../../src/win32-math.h',
|
||||
]}],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
8
deps/v8/tools/presubmit.py
vendored
8
deps/v8/tools/presubmit.py
vendored
@@ -311,13 +311,17 @@ class SourceProcessor(SourceFileProcessor):
|
||||
|
||||
def ProcessFiles(self, files, path):
|
||||
success = True
|
||||
violations = 0
|
||||
for file in files:
|
||||
try:
|
||||
handle = open(file)
|
||||
contents = handle.read()
|
||||
success = self.ProcessContents(file, contents) and success
|
||||
if not self.ProcessContents(file, contents):
|
||||
success = False
|
||||
violations += 1
|
||||
finally:
|
||||
handle.close()
|
||||
print "Total violating files: %s" % violations
|
||||
return success
|
||||
|
||||
|
||||
@@ -333,8 +337,10 @@ def Main():
|
||||
parser = GetOptions()
|
||||
(options, args) = parser.parse_args()
|
||||
success = True
|
||||
print "Running C++ lint check..."
|
||||
if not options.no_lint:
|
||||
success = CppLintProcessor().Run(workspace) and success
|
||||
print "Running copyright header and trailing whitespaces check..."
|
||||
success = SourceProcessor().Run(workspace) and success
|
||||
if success:
|
||||
return 0
|
||||
|
||||
424
deps/v8/tools/push-to-trunk.sh
vendored
Executable file
424
deps/v8/tools/push-to-trunk.sh
vendored
Executable file
@@ -0,0 +1,424 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2011 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.
|
||||
|
||||
|
||||
########## Global variable definitions
|
||||
|
||||
BRANCHNAME=prepare-push
|
||||
TRUNKBRANCH=trunk-push
|
||||
TEMP_BRANCH=v8-push-to-trunk-script-temporary-branch
|
||||
VERSION_FILE="src/version.cc"
|
||||
PERSISTFILE_BASENAME=/tmp/v8-push-to-trunk-tempfile
|
||||
CHANGELOG_ENTRY_FILE="$PERSISTFILE_BASENAME-changelog-entry"
|
||||
PATCH_FILE="$PERSISTFILE_BASENAME-patch"
|
||||
COMMITMSG_FILE="$PERSISTFILE_BASENAME-commitmsg"
|
||||
TOUCHED_FILES_FILE="$PERSISTFILE_BASENAME-touched-files"
|
||||
STEP=0
|
||||
|
||||
|
||||
########## Function definitions
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
usage: $0 OPTIONS
|
||||
|
||||
Performs the necessary steps for a V8 push to trunk. Only works for \
|
||||
git checkouts.
|
||||
|
||||
OPTIONS:
|
||||
-h Show this message
|
||||
-s Specify the step where to start work. Default: 0.
|
||||
-l Manually specify the git commit ID of the last push to trunk.
|
||||
EOF
|
||||
}
|
||||
|
||||
die() {
|
||||
[[ -n "$1" ]] && echo "Error: $1"
|
||||
echo "Exiting."
|
||||
exit 1
|
||||
}
|
||||
|
||||
confirm() {
|
||||
echo -n "$1 [Y/n] "
|
||||
read ANSWER
|
||||
if [[ -z "$ANSWER" || "$ANSWER" == "Y" || "$ANSWER" == "y" ]] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
delete_branch() {
|
||||
local MATCH=$(git branch | grep $1)
|
||||
if [ "$MATCH" == "$1" ] ; then
|
||||
confirm "Branch $1 exists, do you want to delete it?"
|
||||
if [ $? -eq 0 ] ; then
|
||||
git branch -D $1
|
||||
echo "Branch $1 deleted."
|
||||
else
|
||||
die "Can't continue. Please delete branch $1 and try again."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Persist and restore variables to support canceling/resuming execution
|
||||
# of this script.
|
||||
persist() {
|
||||
local VARNAME=$1
|
||||
local FILE="$PERSISTFILE_BASENAME-$VARNAME"
|
||||
echo "${!VARNAME}" > $FILE
|
||||
}
|
||||
|
||||
restore() {
|
||||
local VARNAME=$1
|
||||
local FILE="$PERSISTFILE_BASENAME-$VARNAME"
|
||||
local VALUE="$(cat $FILE)"
|
||||
eval "$VARNAME=\"$VALUE\""
|
||||
}
|
||||
|
||||
restore_if_unset() {
|
||||
local VARNAME=$1
|
||||
[[ -z "${!VARNAME}" ]] && restore "$VARNAME"
|
||||
[[ -z "${!VARNAME}" ]] && die "Variable '$VARNAME' could not be restored."
|
||||
}
|
||||
|
||||
|
||||
########## Option parsing
|
||||
|
||||
while getopts ":hs:l:" OPTION ; do
|
||||
case $OPTION in
|
||||
h) usage
|
||||
exit 0
|
||||
;;
|
||||
s) STEP=$OPTARG
|
||||
;;
|
||||
l) LASTPUSH=$OPTARG
|
||||
;;
|
||||
?) echo "Illegal option: -$OPTARG"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
########## Regular workflow
|
||||
|
||||
# Cancel if this is not a git checkout.
|
||||
[[ -d .git ]] \
|
||||
|| die "This is not a git checkout, this script won't work for you."
|
||||
|
||||
# Cancel if EDITOR is unset or not executable.
|
||||
[[ -n "$EDITOR" && -x "$(which $EDITOR)" ]] \
|
||||
|| die "Please set your EDITOR environment variable, you'll need it."
|
||||
|
||||
if [ $STEP -le 0 ] ; then
|
||||
echo ">>> Step 0: Preparation"
|
||||
# Check for a clean workdir.
|
||||
[[ -z "$(git status -s -uno)" ]] \
|
||||
|| die "Workspace is not clean. Please commit or undo your changes."
|
||||
|
||||
# Persist current branch.
|
||||
CURRENT_BRANCH=$(git status -s -b -uno | grep "^##" | awk '{print $2}')
|
||||
persist "CURRENT_BRANCH"
|
||||
# Get ahold of a safe temporary branch and check it out.
|
||||
if [ "$CURRENT_BRANCH" != "$TEMP_BRANCH" ] ; then
|
||||
delete_branch $TEMP_BRANCH
|
||||
git checkout -b $TEMP_BRANCH
|
||||
fi
|
||||
# Delete branches if they exist.
|
||||
delete_branch $BRANCHNAME
|
||||
delete_branch $TRUNKBRANCH
|
||||
fi
|
||||
|
||||
if [ $STEP -le 1 ] ; then
|
||||
echo ">>> Step 1: Fetch unfetched revisions."
|
||||
git svn fetch || die "'git svn fetch' failed."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 2 ] ; then
|
||||
echo ">>> Step 2: Create a fresh branch."
|
||||
git checkout -b $BRANCHNAME svn/bleeding_edge \
|
||||
|| die "Creating branch $BRANCHNAME failed."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 3 ] ; then
|
||||
echo ">>> Step 3: Detect commit ID of last push to trunk."
|
||||
[[ -n "$LASTPUSH" ]] || LASTPUSH=$(git log -1 --format=%H ChangeLog)
|
||||
LOOP=1
|
||||
while [ $LOOP -eq 1 ] ; do
|
||||
# Print assumed commit, circumventing git's pager.
|
||||
git log -1 $LASTPUSH | cat
|
||||
confirm "Is the commit printed above the last push to trunk?"
|
||||
if [ $? -eq 0 ] ; then
|
||||
LOOP=0
|
||||
else
|
||||
LASTPUSH=$(git log -1 --format=%H $LASTPUSH^ ChangeLog)
|
||||
fi
|
||||
done
|
||||
persist "LASTPUSH"
|
||||
fi
|
||||
|
||||
if [ $STEP -le 4 ] ; then
|
||||
echo ">>> Step 4: Prepare raw ChangeLog entry."
|
||||
# These version numbers are used again later for the trunk commit.
|
||||
MAJOR=$(grep "#define MAJOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
|
||||
persist "MAJOR"
|
||||
MINOR=$(grep "#define MINOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
|
||||
persist "MINOR"
|
||||
BUILD=$(grep "#define BUILD_NUMBER" "$VERSION_FILE" | awk '{print $NF}')
|
||||
persist "BUILD"
|
||||
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
persist "DATE"
|
||||
echo "$DATE: Version $MAJOR.$MINOR.$BUILD" > "$CHANGELOG_ENTRY_FILE"
|
||||
echo "" >> "$CHANGELOG_ENTRY_FILE"
|
||||
COMMITS=$(git log $LASTPUSH..HEAD --format=%H)
|
||||
for commit in $COMMITS ; do
|
||||
# Get the commit's title line.
|
||||
git log -1 $commit --format="%w(80,8,8)%s" >> "$CHANGELOG_ENTRY_FILE"
|
||||
# Grep for "BUG=xxxx" lines in the commit message.
|
||||
git log -1 $commit --format="%b" | grep BUG= | grep -v "BUG=$" \
|
||||
| sed -e 's/^/ /' \
|
||||
>> "$CHANGELOG_ENTRY_FILE"
|
||||
# Append the commit's author for reference.
|
||||
git log -1 $commit --format="%w(80,8,8)(%an)" >> "$CHANGELOG_ENTRY_FILE"
|
||||
echo "" >> "$CHANGELOG_ENTRY_FILE"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ $STEP -le 5 ] ; then
|
||||
echo ">>> Step 5: Edit ChangeLog entry."
|
||||
echo -n "Please press <Return> to have your EDITOR open the ChangeLog entry, \
|
||||
then edit its contents to your liking. When you're done, save the file and \
|
||||
exit your EDITOR. "
|
||||
read ANSWER
|
||||
$EDITOR "$CHANGELOG_ENTRY_FILE"
|
||||
NEWCHANGELOG=$(mktemp)
|
||||
# Eliminate any trailing newlines by going through a shell variable.
|
||||
CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE")
|
||||
[[ -n "$CHANGELOGENTRY" ]] || die "Empty ChangeLog entry."
|
||||
echo "$CHANGELOGENTRY" > "$NEWCHANGELOG"
|
||||
echo "" >> "$NEWCHANGELOG" # Explicitly insert two empty lines.
|
||||
echo "" >> "$NEWCHANGELOG"
|
||||
cat ChangeLog >> "$NEWCHANGELOG"
|
||||
mv "$NEWCHANGELOG" ChangeLog
|
||||
fi
|
||||
|
||||
if [ $STEP -le 6 ] ; then
|
||||
echo ">>> Step 6: Increment version number."
|
||||
restore_if_unset "BUILD"
|
||||
NEWBUILD=$(($BUILD + 1))
|
||||
confirm "Automatically increment BUILD_NUMBER? (Saying 'n' will fire up \
|
||||
your EDITOR on $VERSION_FILE so you can make arbitrary changes. When \
|
||||
you're done, save the file and exit your EDITOR.)"
|
||||
if [ $? -eq 0 ] ; then
|
||||
sed -e "/#define BUILD_NUMBER/s/[0-9]*$/$NEWBUILD/" \
|
||||
-i "$VERSION_FILE"
|
||||
else
|
||||
$EDITOR "$VERSION_FILE"
|
||||
fi
|
||||
NEWMAJOR=$(grep "#define MAJOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
|
||||
persist "NEWMAJOR"
|
||||
NEWMINOR=$(grep "#define MINOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
|
||||
persist "NEWMINOR"
|
||||
NEWBUILD=$(grep "#define BUILD_NUMBER" "$VERSION_FILE" | awk '{print $NF}')
|
||||
persist "NEWBUILD"
|
||||
fi
|
||||
|
||||
if [ $STEP -le 7 ] ; then
|
||||
echo ">>> Step 7: Commit to local branch."
|
||||
restore_if_unset "NEWMAJOR"
|
||||
restore_if_unset "NEWMINOR"
|
||||
restore_if_unset "NEWBUILD"
|
||||
git commit -a -m "Prepare push to trunk. \
|
||||
Now working on version $NEWMAJOR.$NEWMINOR.$NEWBUILD." \
|
||||
|| die "'git commit -a' failed."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 8 ] ; then
|
||||
echo ">>> Step 8: Upload for code review."
|
||||
echo -n "Please enter the email address of a V8 reviewer for your patch: "
|
||||
read REVIEWER
|
||||
git cl upload -r $REVIEWER --send-mail \
|
||||
|| die "'git cl upload' failed, please try again."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 9 ] ; then
|
||||
echo ">>> Step 9: Commit to the repository."
|
||||
echo "Please wait for an LGTM, then type \"LGTM<Return>\" to commit your \
|
||||
change. (If you need to iterate on the patch, do so in another shell.)"
|
||||
unset ANSWER
|
||||
while [ "$ANSWER" != "LGTM" ] ; do
|
||||
[[ -n "$ANSWER" ]] && echo "That was not 'LGTM'."
|
||||
echo -n "> "
|
||||
read ANSWER
|
||||
done
|
||||
# Re-read the ChangeLog entry (to pick up possible changes).
|
||||
cat ChangeLog | awk --posix '{
|
||||
if ($0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}:/) {
|
||||
if (in_firstblock == 1) {
|
||||
exit 0;
|
||||
} else {
|
||||
in_firstblock = 1;
|
||||
}
|
||||
};
|
||||
print $0;
|
||||
}' > "$CHANGELOG_ENTRY_FILE"
|
||||
git cl dcommit || die "'git cl dcommit' failed, please try again."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 10 ] ; then
|
||||
echo ">>> Step 10: NOP"
|
||||
# Present in the manual guide, not necessary (even harmful!) for this script.
|
||||
fi
|
||||
|
||||
if [ $STEP -le 11 ] ; then
|
||||
echo ">>> Step 11: Squash commits into one."
|
||||
# Instead of relying on "git rebase -i", we'll just create a diff, because
|
||||
# that's easier to automate.
|
||||
git diff svn/trunk > "$PATCH_FILE"
|
||||
# Convert the ChangeLog entry to commit message format:
|
||||
# - remove date
|
||||
# - remove indentation
|
||||
# - merge paragraphs into single long lines, keeping empty lines between them.
|
||||
restore_if_unset "DATE"
|
||||
CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE")
|
||||
echo "$CHANGELOGENTRY" \
|
||||
| sed -e "s/^$DATE: //" \
|
||||
| sed -e 's/^ *//' \
|
||||
| awk '{
|
||||
if (need_space == 1) {
|
||||
printf(" ");
|
||||
};
|
||||
printf("%s", $0);
|
||||
if ($0 ~ /^$/) {
|
||||
printf("\n\n");
|
||||
need_space = 0;
|
||||
} else {
|
||||
need_space = 1;
|
||||
}
|
||||
}' > "$COMMITMSG_FILE" || die "Commit message editing failed."
|
||||
LOOP=1
|
||||
while [ $LOOP -eq 1 ] ; do
|
||||
echo "This is the trunk commit message:"
|
||||
echo "--------------------"
|
||||
cat "$COMMITMSG_FILE"
|
||||
echo -e "\n--------------------"
|
||||
confirm "Does this look good to you? (Saying 'n' will fire up your \
|
||||
EDITOR so you can change the commit message. When you're done, save the \
|
||||
file and exit your EDITOR.)"
|
||||
if [ $? -eq 0 ] ; then
|
||||
LOOP=0
|
||||
else
|
||||
$EDITOR "$COMMITMSG_FILE"
|
||||
fi
|
||||
done
|
||||
rm -f "$CHANGELOG_ENTRY_FILE"
|
||||
fi
|
||||
|
||||
if [ $STEP -le 12 ] ; then
|
||||
echo ">>> Step 12: Create a new branch from trunk."
|
||||
git checkout -b $TRUNKBRANCH svn/trunk \
|
||||
|| die "Checking out a new branch '$TRUNKBRANCH' failed."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 13 ] ; then
|
||||
echo ">>> Step 13: Apply squashed changes."
|
||||
patch -p1 < "$PATCH_FILE" | tee >(awk '{print $NF}' >> "$TOUCHED_FILES_FILE")
|
||||
[[ $? -eq 0 ]] || die "Applying the patch to trunk failed."
|
||||
TOUCHED_FILES=$(cat "$TOUCHED_FILES_FILE")
|
||||
for FILE in $TOUCHED_FILES ; do
|
||||
git add "$FILE"
|
||||
done
|
||||
rm -f "$PATCH_FILE"
|
||||
rm -f "$TOUCHED_FILES_FILE"
|
||||
fi
|
||||
|
||||
if [ $STEP -le 14 ] ; then
|
||||
echo ">>> Step 14: Set correct version for trunk."
|
||||
restore_if_unset "MAJOR"
|
||||
restore_if_unset "MINOR"
|
||||
restore_if_unset "BUILD"
|
||||
sed -e "/#define MAJOR_VERSION/s/[0-9]*$/$MAJOR/" \
|
||||
-e "/#define MINOR_VERSION/s/[0-9]*$/$MINOR/" \
|
||||
-e "/#define BUILD_NUMBER/s/[0-9]*$/$BUILD/" \
|
||||
-e "/#define PATCH_LEVEL/s/[0-9]*$/0/" \
|
||||
-e "/#define IS_CANDIDATE_VERSION/s/[0-9]*$/0/" \
|
||||
-i "$VERSION_FILE" || die "Patching $VERSION_FILE failed."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 15 ] ; then
|
||||
echo ">>> Step 15: Commit to local trunk branch."
|
||||
git add "$VERSION_FILE"
|
||||
git commit -F "$COMMITMSG_FILE" || die "'git commit' failed."
|
||||
rm -f "$COMMITMSG_FILE"
|
||||
fi
|
||||
|
||||
if [ $STEP -le 16 ] ; then
|
||||
echo ">>> Step 16: Sanity check."
|
||||
confirm "Please check if your local checkout is sane: Inspect $VERSION_FILE, \
|
||||
compile, run tests. Do you want to commit this new trunk revision to the \
|
||||
repository?"
|
||||
[[ $? -eq 0 ]] || die "Execution canceled."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 17 ] ; then
|
||||
echo ">>> Step 17. Commit to SVN."
|
||||
git svn dcommit || die "'git svn dcommit' failed."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 18 ] ; then
|
||||
echo ">>> Step 18: Tag the new revision."
|
||||
restore_if_unset "MAJOR"
|
||||
restore_if_unset "MINOR"
|
||||
restore_if_unset "BUILD"
|
||||
git svn tag $MAJOR.$MINOR.$BUILD -m "Tagging version $MAJOR.$MINOR.$BUILD" \
|
||||
|| die "'git svn tag' failed."
|
||||
fi
|
||||
|
||||
if [ $STEP -le 19 ] ; then
|
||||
echo ">>> Step 19: Cleanup."
|
||||
restore_if_unset "CURRENT_BRANCH"
|
||||
git checkout -f $CURRENT_BRANCH
|
||||
[[ "$TEMP_BRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TEMP_BRANCH
|
||||
[[ "$BRANCHNAME" != "$CURRENT_BRANCH" ]] && git branch -D $BRANCHNAME
|
||||
[[ "$TRUNKBRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TRUNKBRANCH
|
||||
fi
|
||||
|
||||
if [ $STEP -le 20 ] ; then
|
||||
echo ">>> Step 20: Done!"
|
||||
restore_if_unset "MAJOR"
|
||||
restore_if_unset "MINOR"
|
||||
restore_if_unset "BUILD"
|
||||
echo "Congratulations, you have successfully created the trunk revision \
|
||||
$MAJOR.$MINOR.$BUILD. Please don't forget to update the v8rel spreadsheet, \
|
||||
and to roll this new version into Chromium."
|
||||
# Clean up all temporary files.
|
||||
rm -f "$PERSISTFILE_BASENAME"*
|
||||
fi
|
||||
Reference in New Issue
Block a user