Browse Source

Upgrade V8 to 3.5.7

Ryan Dahl 14 years ago
parent
commit
b15ab5de51
  1. 9
      deps/v8/ChangeLog
  2. 40
      deps/v8/build/common.gypi
  3. 485
      deps/v8/samples/shell.cc
  4. 4
      deps/v8/src/api.h
  5. 12
      deps/v8/src/arm/full-codegen-arm.cc
  6. 371
      deps/v8/src/elements.cc
  7. 38
      deps/v8/src/elements.h
  8. 51
      deps/v8/src/full-codegen.cc
  9. 113
      deps/v8/src/full-codegen.h
  10. 17
      deps/v8/src/ia32/full-codegen-ia32.cc
  11. 2
      deps/v8/src/ia32/macro-assembler-ia32.cc
  12. 6
      deps/v8/src/isolate.cc
  13. 52
      deps/v8/src/messages.js
  14. 18
      deps/v8/src/mips/full-codegen-mips.cc
  15. 82
      deps/v8/src/objects.cc
  16. 15
      deps/v8/src/regexp.js
  17. 93
      deps/v8/src/scanner-base.cc
  18. 6
      deps/v8/src/scanner-base.h
  19. 1
      deps/v8/src/spaces.h
  20. 2
      deps/v8/src/string.js
  21. 30
      deps/v8/src/v8natives.js
  22. 4
      deps/v8/src/v8threads.cc
  23. 2
      deps/v8/src/version.cc
  24. 12
      deps/v8/src/x64/full-codegen-x64.cc
  25. 46
      deps/v8/test/cctest/test-api.cc
  26. 54
      deps/v8/test/mjsunit/regress/regress-1620.js
  27. 36
      deps/v8/test/mjsunit/regress/regress-1625.js
  28. 128
      deps/v8/test/mjsunit/regress/regress-219.js
  29. 57
      deps/v8/test/mjsunit/regress/regress-87.js
  30. 5
      deps/v8/test/mozilla/mozilla.status
  31. 16
      deps/v8/test/sputnik/sputnik.status
  32. 6
      deps/v8/tools/gyp/v8.gyp

9
deps/v8/ChangeLog

@ -1,3 +1,12 @@
2011-08-22: Version 3.5.7
Make scanner handle invalid unicode escapes in identifiers correctly.
Make regexp flag parsing stricter.
Fix several memory leaks.
2011-08-17: Version 3.5.6 2011-08-17: Version 3.5.6
Fixed issue that could cause crashes when running with --heap-stats. Fixed issue that could cause crashes when running with --heap-stats.

40
deps/v8/build/common.gypi

@ -32,25 +32,30 @@
'visibility%': 'hidden', 'visibility%': 'hidden',
'msvs_multi_core_compile%': '1', 'msvs_multi_core_compile%': '1',
'variables': { 'variables': {
'conditions': [ 'variables': {
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { 'conditions': [
# This handles the Linux platforms we generally deal with. Anything [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
# else gets passed through, which probably won't work very well; such # This handles the Linux platforms we generally deal with. Anything
# hosts should pass an explicit target_arch to gyp. # else gets passed through, which probably won't work very well; such
'host_arch%': # hosts should pass an explicit target_arch to gyp.
'<!(uname -m | sed -e "s/i.86/ia32/;s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/")', 'host_arch%':
}, { # OS!="linux" and OS!="freebsd" and OS!="openbsd" '<!(uname -m | sed -e "s/i.86/ia32/;s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/")',
'host_arch%': 'ia32', }, { # OS!="linux" and OS!="freebsd" and OS!="openbsd"
}], 'host_arch%': 'ia32',
], }],
],
},
'host_arch%': '<(host_arch)',
'target_arch%': '<(host_arch)',
'v8_target_arch%': '<(target_arch)',
}, },
'host_arch%': '<(host_arch)', 'host_arch%': '<(host_arch)',
'target_arch%': '<(host_arch)', 'target_arch%': '<(target_arch)',
'v8_target_arch%': '<(target_arch)', 'v8_target_arch%': '<(v8_target_arch)',
'v8_enable_debugger_support%': 1, 'v8_enable_debugger_support%': 1,
'conditions': [ 'conditions': [
['(target_arch=="arm" and host_arch!="arm") or \ ['(v8_target_arch=="arm" and host_arch!="arm") or \
(target_arch=="x64" and host_arch!="x64")', { (v8_target_arch=="x64" and host_arch!="x64")', {
'want_separate_host_toolset': 1, 'want_separate_host_toolset': 1,
}, { }, {
'want_separate_host_toolset': 0, 'want_separate_host_toolset': 0,
@ -80,8 +85,9 @@
'conditions': [ 'conditions': [
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
'target_defaults': { 'target_defaults': {
'cflags': [ '-Wall', '-pthread', '-fno-rtti', '-fno-exceptions', 'cflags': [ '-Wall', '-Werror', '-W', '-Wno-unused-parameter',
'-pedantic' ], '-Wnon-virtual-dtor', '-pthread', '-fno-rtti',
'-fno-exceptions', '-pedantic' ],
'ldflags': [ '-pthread', ], 'ldflags': [ '-pthread', ],
'conditions': [ 'conditions': [
[ 'target_arch=="ia32"', { [ 'target_arch=="ia32"', {

485
deps/v8/samples/shell.cc

@ -26,39 +26,28 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <v8.h> #include <v8.h>
#include <v8-testing.h>
#include <assert.h> #include <assert.h>
#ifdef COMPRESS_STARTUP_DATA_BZ2
#include <bzlib.h>
#endif
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
// When building with V8 in a shared library we cannot use functions which #ifdef COMPRESS_STARTUP_DATA_BZ2
// is not explicitly a part of the public V8 API. This extensive use of #error Using compressed startup data is not supported for this sample
// #ifndef USING_V8_SHARED/#endif is a hack until we can resolve whether to
// still use the shell sample for testing or change to use the developer
// shell d8 TODO(1272).
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
#include "../src/v8.h"
#endif // USING_V8_SHARED
#if !defined(_WIN32) && !defined(_WIN64)
#include <unistd.h> // NOLINT
#endif #endif
static void ExitShell(int exit_code) { /**
// Use _exit instead of exit to avoid races between isolate * This sample program shows how to implement a simple javascript shell
// threads and static destructors. * based on V8. This includes initializing V8 with command line options,
fflush(stdout); * creating global functions, compiling and executing strings.
fflush(stderr); *
_exit(exit_code); * For a more sophisticated shell, consider using the debug shell D8.
} */
v8::Persistent<v8::Context> CreateShellContext(); v8::Persistent<v8::Context> CreateShellContext();
void RunShell(v8::Handle<v8::Context> context); void RunShell(v8::Handle<v8::Context> context);
int RunMain(int argc, char* argv[]);
bool ExecuteString(v8::Handle<v8::String> source, bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name, v8::Handle<v8::Value> name,
bool print_result, bool print_result,
@ -68,305 +57,28 @@ v8::Handle<v8::Value> Read(const v8::Arguments& args);
v8::Handle<v8::Value> Load(const v8::Arguments& args); v8::Handle<v8::Value> Load(const v8::Arguments& args);
v8::Handle<v8::Value> Quit(const v8::Arguments& args); v8::Handle<v8::Value> Quit(const v8::Arguments& args);
v8::Handle<v8::Value> Version(const v8::Arguments& args); v8::Handle<v8::Value> Version(const v8::Arguments& args);
v8::Handle<v8::Value> Int8Array(const v8::Arguments& args);
v8::Handle<v8::Value> Uint8Array(const v8::Arguments& args);
v8::Handle<v8::Value> Int16Array(const v8::Arguments& args);
v8::Handle<v8::Value> Uint16Array(const v8::Arguments& args);
v8::Handle<v8::Value> Int32Array(const v8::Arguments& args);
v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args);
v8::Handle<v8::Value> Float32Array(const v8::Arguments& args);
v8::Handle<v8::Value> Float64Array(const v8::Arguments& args);
v8::Handle<v8::Value> PixelArray(const v8::Arguments& args);
v8::Handle<v8::String> ReadFile(const char* name); v8::Handle<v8::String> ReadFile(const char* name);
void ReportException(v8::TryCatch* handler); void ReportException(v8::TryCatch* handler);
static bool last_run = true; static bool run_shell;
class SourceGroup {
public:
SourceGroup() :
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
thread_(NULL),
#endif // USING_V8_SHARED
argv_(NULL),
begin_offset_(0),
end_offset_(0) { }
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
~SourceGroup() {
delete next_semaphore_;
delete done_semaphore_;
}
#endif // USING_V8_SHARED
void Begin(char** argv, int offset) {
argv_ = const_cast<const char**>(argv);
begin_offset_ = offset;
}
void End(int offset) { end_offset_ = offset; }
void Execute() {
for (int i = begin_offset_; i < end_offset_; ++i) {
const char* arg = argv_[i];
if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
// Execute argument given to -e option directly.
v8::HandleScope handle_scope;
v8::Handle<v8::String> file_name = v8::String::New("unnamed");
v8::Handle<v8::String> source = v8::String::New(argv_[i + 1]);
if (!ExecuteString(source, file_name, false, true)) {
ExitShell(1);
return;
}
++i;
} else if (arg[0] == '-') {
// Ignore other options. They have been parsed already.
} else {
// Use all other arguments as names of files to load and run.
v8::HandleScope handle_scope;
v8::Handle<v8::String> file_name = v8::String::New(arg);
v8::Handle<v8::String> source = ReadFile(arg);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", arg);
continue;
}
if (!ExecuteString(source, file_name, false, true)) {
ExitShell(1);
return;
}
}
}
}
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
void StartExecuteInThread() {
if (thread_ == NULL) {
thread_ = new IsolateThread(this);
thread_->Start();
}
next_semaphore_->Signal();
}
void WaitForThread() {
if (thread_ == NULL) return;
if (last_run) {
thread_->Join();
thread_ = NULL;
} else {
done_semaphore_->Wait();
}
}
#endif // USING_V8_SHARED
private:
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
static v8::internal::Thread::Options GetThreadOptions() {
v8::internal::Thread::Options options;
options.name = "IsolateThread";
// On some systems (OSX 10.6) the stack size default is 0.5Mb or less
// which is not enough to parse the big literal expressions used in tests.
// The stack size should be at least StackGuard::kLimitSize + some
// OS-specific padding for thread startup code.
options.stack_size = 2 << 20; // 2 Mb seems to be enough
return options;
}
class IsolateThread : public v8::internal::Thread {
public:
explicit IsolateThread(SourceGroup* group)
: v8::internal::Thread(GetThreadOptions()), group_(group) {}
virtual void Run() {
group_->ExecuteInThread();
}
private:
SourceGroup* group_;
};
void ExecuteInThread() {
v8::Isolate* isolate = v8::Isolate::New();
do {
if (next_semaphore_ != NULL) next_semaphore_->Wait();
{
v8::Isolate::Scope iscope(isolate);
v8::HandleScope scope;
v8::Persistent<v8::Context> context = CreateShellContext();
{
v8::Context::Scope cscope(context);
Execute();
}
context.Dispose();
}
if (done_semaphore_ != NULL) done_semaphore_->Signal();
} while (!last_run);
isolate->Dispose();
}
v8::internal::Semaphore* next_semaphore_;
v8::internal::Semaphore* done_semaphore_;
v8::internal::Thread* thread_;
#endif // USING_V8_SHARED
const char** argv_;
int begin_offset_;
int end_offset_;
};
static SourceGroup* isolate_sources = NULL;
int main(int argc, char* argv[]) {
#ifdef COMPRESS_STARTUP_DATA_BZ2
class BZip2Decompressor : public v8::StartupDataDecompressor {
public:
virtual ~BZip2Decompressor() { }
protected:
virtual int DecompressData(char* raw_data,
int* raw_data_size,
const char* compressed_data,
int compressed_data_size) {
ASSERT_EQ(v8::StartupData::kBZip2,
v8::V8::GetCompressedStartupDataAlgorithm());
unsigned int decompressed_size = *raw_data_size;
int result =
BZ2_bzBuffToBuffDecompress(raw_data,
&decompressed_size,
const_cast<char*>(compressed_data),
compressed_data_size,
0, 1);
if (result == BZ_OK) {
*raw_data_size = decompressed_size;
}
return result;
}
};
#endif
int RunMain(int argc, char* argv[]) {
v8::V8::SetFlagsFromCommandLine(&argc, argv, true); v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
run_shell = (argc == 1);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Persistent<v8::Context> context = CreateShellContext(); v8::Persistent<v8::Context> context = CreateShellContext();
// Enter the newly created execution environment.
context->Enter();
if (context.IsEmpty()) { if (context.IsEmpty()) {
printf("Error creating context\n"); printf("Error creating context\n");
return 1; return 1;
} }
context->Enter();
bool run_shell = (argc == 1); int result = RunMain(argc, argv);
int num_isolates = 1;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--isolate") == 0) {
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
++num_isolates;
#else // USING_V8_SHARED
printf("Error: --isolate not supported when linked with shared "
"library\n");
ExitShell(1);
#endif // USING_V8_SHARED
}
}
if (isolate_sources == NULL) {
isolate_sources = new SourceGroup[num_isolates];
SourceGroup* current = isolate_sources;
current->Begin(argv, 1);
for (int i = 1; i < argc; i++) {
const char* str = argv[i];
if (strcmp(str, "--isolate") == 0) {
current->End(i);
current++;
current->Begin(argv, i + 1);
} else if (strcmp(str, "--shell") == 0) {
run_shell = true;
} else if (strcmp(str, "-f") == 0) {
// Ignore any -f flags for compatibility with the other stand-
// alone JavaScript engines.
continue;
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\nTry --help for options\n", str);
}
}
current->End(argc);
}
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
for (int i = 1; i < num_isolates; ++i) {
isolate_sources[i].StartExecuteInThread();
}
#endif // USING_V8_SHARED
isolate_sources[0].Execute();
if (run_shell) RunShell(context); if (run_shell) RunShell(context);
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
for (int i = 1; i < num_isolates; ++i) {
isolate_sources[i].WaitForThread();
}
#endif // USING_V8_SHARED
if (last_run) {
delete[] isolate_sources;
isolate_sources = NULL;
}
context->Exit(); context->Exit();
context.Dispose(); context.Dispose();
return 0;
}
int main(int argc, char* argv[]) {
// Figure out if we're requested to stress the optimization
// infrastructure by running tests multiple times and forcing
// optimization in the last run.
bool FLAG_stress_opt = false;
bool FLAG_stress_deopt = false;
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "--stress-opt") == 0) {
FLAG_stress_opt = true;
argv[i] = NULL;
} else if (strcmp(argv[i], "--stress-deopt") == 0) {
FLAG_stress_deopt = true;
argv[i] = NULL;
} else if (strcmp(argv[i], "--noalways-opt") == 0) {
// No support for stressing if we can't use --always-opt.
FLAG_stress_opt = false;
FLAG_stress_deopt = false;
break;
}
}
#ifdef COMPRESS_STARTUP_DATA_BZ2
BZip2Decompressor startup_data_decompressor;
int bz2_result = startup_data_decompressor.Decompress();
if (bz2_result != BZ_OK) {
fprintf(stderr, "bzip error code: %d\n", bz2_result);
exit(1);
}
#endif
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
int result = 0;
if (FLAG_stress_opt || FLAG_stress_deopt) {
v8::Testing::SetStressRunType(FLAG_stress_opt
? v8::Testing::kStressTypeOpt
: v8::Testing::kStressTypeDeopt);
int stress_runs = v8::Testing::GetStressRuns();
for (int i = 0; i < stress_runs && result == 0; i++) {
printf("============ Stress %d/%d ============\n",
i + 1, stress_runs);
v8::Testing::PrepareStressRun(i);
last_run = (i == stress_runs - 1);
result = RunMain(argc, argv);
}
printf("======== Full Deoptimization =======\n");
v8::Testing::DeoptimizeAll();
} else {
result = RunMain(argc, argv);
}
v8::V8::Dispose(); v8::V8::Dispose();
return result; return result;
} }
@ -393,26 +105,6 @@ v8::Persistent<v8::Context> CreateShellContext() {
// Bind the 'version' function // Bind the 'version' function
global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version)); global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
// Bind the handlers for external arrays.
global->Set(v8::String::New("Int8Array"),
v8::FunctionTemplate::New(Int8Array));
global->Set(v8::String::New("Uint8Array"),
v8::FunctionTemplate::New(Uint8Array));
global->Set(v8::String::New("Int16Array"),
v8::FunctionTemplate::New(Int16Array));
global->Set(v8::String::New("Uint16Array"),
v8::FunctionTemplate::New(Uint16Array));
global->Set(v8::String::New("Int32Array"),
v8::FunctionTemplate::New(Int32Array));
global->Set(v8::String::New("Uint32Array"),
v8::FunctionTemplate::New(Uint32Array));
global->Set(v8::String::New("Float32Array"),
v8::FunctionTemplate::New(Float32Array));
global->Set(v8::String::New("Float64Array"),
v8::FunctionTemplate::New(Float64Array));
global->Set(v8::String::New("PixelArray"),
v8::FunctionTemplate::New(PixelArray));
return v8::Context::New(NULL, global); return v8::Context::New(NULL, global);
} }
@ -486,7 +178,9 @@ v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
// If not arguments are given args[0] will yield undefined which // If not arguments are given args[0] will yield undefined which
// converts to the integer value 0. // converts to the integer value 0.
int exit_code = args[0]->Int32Value(); int exit_code = args[0]->Int32Value();
ExitShell(exit_code); fflush(stdout);
fflush(stderr);
exit(exit_code);
return v8::Undefined(); return v8::Undefined();
} }
@ -496,113 +190,6 @@ v8::Handle<v8::Value> Version(const v8::Arguments& args) {
} }
void ExternalArrayWeakCallback(v8::Persistent<v8::Value> object, void* data) {
free(data);
object.Dispose();
}
v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args,
v8::ExternalArrayType type,
size_t element_size) {
assert(element_size == 1 ||
element_size == 2 ||
element_size == 4 ||
element_size == 8);
if (args.Length() != 1) {
return v8::ThrowException(
v8::String::New("Array constructor needs one parameter."));
}
static const int kMaxLength = 0x3fffffff;
size_t length = 0;
if (args[0]->IsUint32()) {
length = args[0]->Uint32Value();
} else if (args[0]->IsNumber()) {
double raw_length = args[0]->NumberValue();
if (raw_length < 0) {
return v8::ThrowException(
v8::String::New("Array length must not be negative."));
}
if (raw_length > kMaxLength) {
return v8::ThrowException(
v8::String::New("Array length exceeds maximum length."));
}
length = static_cast<size_t>(raw_length);
} else {
return v8::ThrowException(
v8::String::New("Array length must be a number."));
}
if (length > static_cast<size_t>(kMaxLength)) {
return v8::ThrowException(
v8::String::New("Array length exceeds maximum length."));
}
void* data = calloc(length, element_size);
if (data == NULL) {
return v8::ThrowException(v8::String::New("Memory allocation failed."));
}
v8::Handle<v8::Object> array = v8::Object::New();
v8::Persistent<v8::Object> persistent_array =
v8::Persistent<v8::Object>::New(array);
persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
persistent_array.MarkIndependent();
array->SetIndexedPropertiesToExternalArrayData(data, type, length);
array->Set(v8::String::New("length"), v8::Int32::New(length),
v8::ReadOnly);
array->Set(v8::String::New("BYTES_PER_ELEMENT"),
v8::Int32::New(element_size));
return array;
}
v8::Handle<v8::Value> Int8Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
}
v8::Handle<v8::Value> Uint8Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalUnsignedByteArray,
sizeof(uint8_t));
}
v8::Handle<v8::Value> Int16Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalShortArray, sizeof(int16_t));
}
v8::Handle<v8::Value> Uint16Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalUnsignedShortArray,
sizeof(uint16_t));
}
v8::Handle<v8::Value> Int32Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalIntArray, sizeof(int32_t));
}
v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalUnsignedIntArray,
sizeof(uint32_t));
}
v8::Handle<v8::Value> Float32Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalFloatArray,
sizeof(float)); // NOLINT
}
v8::Handle<v8::Value> Float64Array(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalDoubleArray,
sizeof(double)); // NOLINT
}
v8::Handle<v8::Value> PixelArray(const v8::Arguments& args) {
return CreateExternalArray(args, v8::kExternalPixelArray, sizeof(uint8_t));
}
// Reads a file into a v8 string. // Reads a file into a v8 string.
v8::Handle<v8::String> ReadFile(const char* name) { v8::Handle<v8::String> ReadFile(const char* name) {
FILE* file = fopen(name, "rb"); FILE* file = fopen(name, "rb");
@ -625,9 +212,41 @@ v8::Handle<v8::String> ReadFile(const char* name) {
} }
// Process remaining command line arguments and execute files
int RunMain(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
const char* str = argv[i];
if (strcmp(str, "--shell") == 0) {
run_shell = true;
} else if (strcmp(str, "-f") == 0) {
// Ignore any -f flags for compatibility with the other stand-
// alone JavaScript engines.
continue;
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
// Execute argument given to -e option directly.
v8::Handle<v8::String> file_name = v8::String::New("unnamed");
v8::Handle<v8::String> source = v8::String::New(argv[++i]);
if (!ExecuteString(source, file_name, false, true)) return 1;
} else {
// Use all other arguments as names of files to load and run.
v8::Handle<v8::String> file_name = v8::String::New(str);
v8::Handle<v8::String> source = ReadFile(str);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", str);
continue;
}
if (!ExecuteString(source, file_name, false, true)) return 1;
}
}
return 0;
}
// The read-eval-execute loop of the shell. // The read-eval-execute loop of the shell.
void RunShell(v8::Handle<v8::Context> context) { void RunShell(v8::Handle<v8::Context> context) {
printf("V8 version %s\n", v8::V8::GetVersion()); printf("V8 version %s [sample shell]\n", v8::V8::GetVersion());
static const int kBufferSize = 256; static const int kBufferSize = 256;
// Enter the execution environment before evaluating any code. // Enter the execution environment before evaluating any code.
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);

4
deps/v8/src/api.h

@ -406,6 +406,10 @@ class HandleScopeImplementer {
spare_(NULL), spare_(NULL),
call_depth_(0) { } call_depth_(0) { }
~HandleScopeImplementer() {
DeleteArray(spare_);
}
// Threading support for handle data. // Threading support for handle data.
static int ArchiveSpacePerThread(); static int ArchiveSpacePerThread();
char* RestoreThread(char* from); char* RestoreThread(char* from);

12
deps/v8/src/arm/full-codegen-arm.cc

@ -878,7 +878,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
__ bind(&next_test); __ bind(&next_test);
__ Drop(1); // Switch value is no longer needed. __ Drop(1); // Switch value is no longer needed.
if (default_clause == NULL) { if (default_clause == NULL) {
__ b(nested_statement.break_target()); __ b(nested_statement.break_label());
} else { } else {
__ b(default_clause->body_target()); __ b(default_clause->body_target());
} }
@ -892,7 +892,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
VisitStatements(clause->statements()); VisitStatements(clause->statements());
} }
__ bind(nested_statement.break_target()); __ bind(nested_statement.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
@ -1023,7 +1023,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Load the current count to r0, load the length to r1. // Load the current count to r0, load the length to r1.
__ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize)); __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
__ cmp(r0, r1); // Compare to the array length. __ cmp(r0, r1); // Compare to the array length.
__ b(hs, loop_statement.break_target()); __ b(hs, loop_statement.break_label());
// Get the current entry of the array into register r3. // Get the current entry of the array into register r3.
__ ldr(r2, MemOperand(sp, 2 * kPointerSize)); __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
@ -1049,7 +1049,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(r3); // Current entry. __ push(r3); // Current entry.
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
__ mov(r3, Operand(r0), SetCC); __ mov(r3, Operand(r0), SetCC);
__ b(eq, loop_statement.continue_target()); __ b(eq, loop_statement.continue_label());
// Update the 'each' property or variable from the possibly filtered // Update the 'each' property or variable from the possibly filtered
// entry in register r3. // entry in register r3.
@ -1065,7 +1065,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for the going to the next element by incrementing // Generate code for the going to the next element by incrementing
// the index (smi) stored on top of the stack. // the index (smi) stored on top of the stack.
__ bind(loop_statement.continue_target()); __ bind(loop_statement.continue_label());
__ pop(r0); __ pop(r0);
__ add(r0, r0, Operand(Smi::FromInt(1))); __ add(r0, r0, Operand(Smi::FromInt(1)));
__ push(r0); __ push(r0);
@ -1074,7 +1074,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ b(&loop); __ b(&loop);
// Remove the pointers stored on the stack. // Remove the pointers stored on the stack.
__ bind(loop_statement.break_target()); __ bind(loop_statement.break_label());
__ Drop(5); __ Drop(5);
// Exit and decrement the loop depth. // Exit and decrement the loop depth.

371
deps/v8/src/elements.cc

@ -29,6 +29,7 @@
#include "objects.h" #include "objects.h"
#include "elements.h" #include "elements.h"
#include "utils.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -70,24 +71,34 @@ bool HasKey(FixedArray* array, Object* key) {
// specialization of SomeElementsAccessor methods). // specialization of SomeElementsAccessor methods).
template <typename ElementsAccessorSubclass, typename BackingStoreClass> template <typename ElementsAccessorSubclass, typename BackingStoreClass>
class ElementsAccessorBase : public ElementsAccessor { class ElementsAccessorBase : public ElementsAccessor {
public: protected:
ElementsAccessorBase() { } ElementsAccessorBase() { }
virtual MaybeObject* GetWithReceiver(JSObject* obj, virtual MaybeObject* Get(FixedArrayBase* backing_store,
Object* receiver, uint32_t key,
uint32_t index) { JSObject* obj,
BackingStoreClass* backing_store = BackingStoreClass::cast(obj->elements()); Object* receiver) {
if (index < ElementsAccessorSubclass::GetLength(backing_store)) { return ElementsAccessorSubclass::Get(
return backing_store->get(index); BackingStoreClass::cast(backing_store), key, obj, receiver);
}
static MaybeObject* Get(BackingStoreClass* backing_store,
uint32_t key,
JSObject* obj,
Object* receiver) {
if (key < ElementsAccessorSubclass::GetCapacity(backing_store)) {
return backing_store->get(key);
} }
return obj->GetHeap()->the_hole_value(); return backing_store->GetHeap()->the_hole_value();
} }
virtual MaybeObject* Delete(JSObject* obj, virtual MaybeObject* Delete(JSObject* obj,
uint32_t index, uint32_t key,
JSReceiver::DeleteMode mode) = 0; JSReceiver::DeleteMode mode) = 0;
virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
FixedArray* to) { FixedArray* to,
JSObject* holder,
Object* receiver) {
int len0 = to->length(); int len0 = to->length();
#ifdef DEBUG #ifdef DEBUG
if (FLAG_enable_slow_asserts) { if (FLAG_enable_slow_asserts) {
@ -97,7 +108,7 @@ class ElementsAccessorBase : public ElementsAccessor {
} }
#endif #endif
BackingStoreClass* backing_store = BackingStoreClass::cast(from); BackingStoreClass* backing_store = BackingStoreClass::cast(from);
int len1 = ElementsAccessorSubclass::GetCapacity(backing_store); uint32_t len1 = ElementsAccessorSubclass::GetCapacity(backing_store);
// Optimize if 'other' is empty. // Optimize if 'other' is empty.
// We cannot optimize if 'this' is empty, as other may have holes. // We cannot optimize if 'this' is empty, as other may have holes.
@ -105,12 +116,22 @@ class ElementsAccessorBase : public ElementsAccessor {
// Compute how many elements are not in other. // Compute how many elements are not in other.
int extra = 0; int extra = 0;
for (int y = 0; y < len1; y++) { for (uint32_t y = 0; y < len1; y++) {
Object* value; if (ElementsAccessorSubclass::HasElementAtIndex(backing_store,
MaybeObject* maybe_value = y,
ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); holder,
if (!maybe_value->ToObject(&value)) return maybe_value; receiver)) {
if (!value->IsTheHole() && !HasKey(to, value)) extra++; uint32_t key =
ElementsAccessorSubclass::GetKeyForIndex(backing_store, y);
MaybeObject* maybe_value =
ElementsAccessorSubclass::Get(backing_store, key, holder, receiver);
Object* value;
if (!maybe_value->ToObject(&value)) return maybe_value;
ASSERT(!value->IsTheHole());
if (!HasKey(to, value)) {
extra++;
}
}
} }
if (extra == 0) return to; if (extra == 0) return to;
@ -133,32 +154,67 @@ class ElementsAccessorBase : public ElementsAccessor {
} }
// Fill in the extra values. // Fill in the extra values.
int index = 0; int index = 0;
for (int y = 0; y < len1; y++) { for (uint32_t y = 0; y < len1; y++) {
MaybeObject* maybe_value = if (ElementsAccessorSubclass::HasElementAtIndex(backing_store,
ElementsAccessorSubclass::GetElementAtCapacityIndex(backing_store, y); y,
Object* value; holder,
if (!maybe_value->ToObject(&value)) return maybe_value; receiver)) {
if (!value->IsTheHole() && !HasKey(to, value)) { uint32_t key =
result->set(len0 + index, value); ElementsAccessorSubclass::GetKeyForIndex(backing_store, y);
index++; MaybeObject* maybe_value =
ElementsAccessorSubclass::Get(backing_store, key, holder, receiver);
Object* value;
if (!maybe_value->ToObject(&value)) return maybe_value;
if (!value->IsTheHole() && !HasKey(to, value)) {
result->set(len0 + index, value);
index++;
}
} }
} }
ASSERT(extra == index); ASSERT(extra == index);
return result; return result;
} }
static uint32_t GetLength(BackingStoreClass* backing_store) { protected:
static uint32_t GetCapacity(BackingStoreClass* backing_store) {
return backing_store->length(); return backing_store->length();
} }
static uint32_t GetCapacity(BackingStoreClass* backing_store) { virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
return GetLength(backing_store); return ElementsAccessorSubclass::GetCapacity(
BackingStoreClass::cast(backing_store));
} }
static MaybeObject* GetElementAtCapacityIndex( static bool HasElementAtIndex(BackingStoreClass* backing_store,
BackingStoreClass* backing_store, uint32_t index,
int index) { JSObject* holder,
return backing_store->get(index); Object* receiver) {
uint32_t key =
ElementsAccessorSubclass::GetKeyForIndex(backing_store, index);
MaybeObject* element = ElementsAccessorSubclass::Get(backing_store,
key,
holder,
receiver);
return !element->IsTheHole();
}
virtual bool HasElementAtIndex(FixedArrayBase* backing_store,
uint32_t index,
JSObject* holder,
Object* receiver) {
return ElementsAccessorSubclass::HasElementAtIndex(
BackingStoreClass::cast(backing_store), index, holder, receiver);
}
static uint32_t GetKeyForIndex(BackingStoreClass* backing_store,
uint32_t index) {
return index;
}
virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
uint32_t index) {
return ElementsAccessorSubclass::GetKeyForIndex(
BackingStoreClass::cast(backing_store), index);
} }
private: private:
@ -170,7 +226,7 @@ class FastElementsAccessor
: public ElementsAccessorBase<FastElementsAccessor, FixedArray> { : public ElementsAccessorBase<FastElementsAccessor, FixedArray> {
public: public:
static MaybeObject* DeleteCommon(JSObject* obj, static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t index) { uint32_t key) {
ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements()); ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements());
Heap* heap = obj->GetHeap(); Heap* heap = obj->GetHeap();
FixedArray* backing_store = FixedArray::cast(obj->elements()); FixedArray* backing_store = FixedArray::cast(obj->elements());
@ -186,8 +242,8 @@ class FastElementsAccessor
obj->IsJSArray() obj->IsJSArray()
? Smi::cast(JSArray::cast(obj)->length())->value() ? Smi::cast(JSArray::cast(obj)->length())->value()
: backing_store->length()); : backing_store->length());
if (index < length) { if (key < length) {
backing_store->set_the_hole(index); backing_store->set_the_hole(key);
// If an old space backing store is larger than a certain size and // If an old space backing store is larger than a certain size and
// has too few used values, normalize it. // has too few used values, normalize it.
// To avoid doing the check on every delete we require at least // To avoid doing the check on every delete we require at least
@ -196,8 +252,8 @@ class FastElementsAccessor
const int kMinLengthForSparsenessCheck = 64; const int kMinLengthForSparsenessCheck = 64;
if (backing_store->length() >= kMinLengthForSparsenessCheck && if (backing_store->length() >= kMinLengthForSparsenessCheck &&
!heap->InNewSpace(backing_store) && !heap->InNewSpace(backing_store) &&
((index > 0 && backing_store->get(index - 1) == hole) || ((key > 0 && backing_store->get(key - 1) == hole) ||
(index + 1 < length && backing_store->get(index + 1) == hole))) { (key + 1 < length && backing_store->get(key + 1) == hole))) {
int num_used = 0; int num_used = 0;
for (int i = 0; i < backing_store->length(); ++i) { for (int i = 0; i < backing_store->length(); ++i) {
if (backing_store->get(i) != hole) ++num_used; if (backing_store->get(i) != hole) ++num_used;
@ -213,10 +269,11 @@ class FastElementsAccessor
return heap->true_value(); return heap->true_value();
} }
protected:
virtual MaybeObject* Delete(JSObject* obj, virtual MaybeObject* Delete(JSObject* obj,
uint32_t index, uint32_t key,
JSReceiver::DeleteMode mode) { JSReceiver::DeleteMode mode) {
return DeleteCommon(obj, index); return DeleteCommon(obj, key);
} }
}; };
@ -224,17 +281,28 @@ class FastElementsAccessor
class FastDoubleElementsAccessor class FastDoubleElementsAccessor
: public ElementsAccessorBase<FastDoubleElementsAccessor, : public ElementsAccessorBase<FastDoubleElementsAccessor,
FixedDoubleArray> { FixedDoubleArray> {
protected:
friend class ElementsAccessorBase<FastDoubleElementsAccessor,
FixedDoubleArray>;
virtual MaybeObject* Delete(JSObject* obj, virtual MaybeObject* Delete(JSObject* obj,
uint32_t index, uint32_t key,
JSReceiver::DeleteMode mode) { JSReceiver::DeleteMode mode) {
int length = obj->IsJSArray() int length = obj->IsJSArray()
? Smi::cast(JSArray::cast(obj)->length())->value() ? Smi::cast(JSArray::cast(obj)->length())->value()
: FixedDoubleArray::cast(obj->elements())->length(); : FixedDoubleArray::cast(obj->elements())->length();
if (index < static_cast<uint32_t>(length)) { if (key < static_cast<uint32_t>(length)) {
FixedDoubleArray::cast(obj->elements())->set_the_hole(index); FixedDoubleArray::cast(obj->elements())->set_the_hole(key);
} }
return obj->GetHeap()->true_value(); return obj->GetHeap()->true_value();
} }
static bool HasElementAtIndex(FixedDoubleArray* backing_store,
uint32_t index,
JSObject* holder,
Object* receiver) {
return !backing_store->is_the_hole(index);
}
}; };
@ -244,20 +312,23 @@ template<typename ExternalElementsAccessorSubclass,
class ExternalElementsAccessor class ExternalElementsAccessor
: public ElementsAccessorBase<ExternalElementsAccessorSubclass, : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
ExternalArray> { ExternalArray> {
public: protected:
virtual MaybeObject* GetWithReceiver(JSObject* obj, friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
Object* receiver, ExternalArray>;
uint32_t index) {
ExternalArray* backing_store = ExternalArray::cast(obj->elements()); static MaybeObject* Get(ExternalArray* backing_store,
if (index < ExternalElementsAccessorSubclass::GetLength(backing_store)) { uint32_t key,
return backing_store->get(index); JSObject* obj,
Object* receiver) {
if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) {
return backing_store->get(key);
} else { } else {
return obj->GetHeap()->undefined_value(); return backing_store->GetHeap()->undefined_value();
} }
} }
virtual MaybeObject* Delete(JSObject* obj, virtual MaybeObject* Delete(JSObject* obj,
uint32_t index, uint32_t key,
JSReceiver::DeleteMode mode) { JSReceiver::DeleteMode mode) {
// External arrays always ignore deletes. // External arrays always ignore deletes.
return obj->GetHeap()->true_value(); return obj->GetHeap()->true_value();
@ -323,30 +394,8 @@ class DictionaryElementsAccessor
: public ElementsAccessorBase<DictionaryElementsAccessor, : public ElementsAccessorBase<DictionaryElementsAccessor,
NumberDictionary> { NumberDictionary> {
public: public:
static MaybeObject* GetNumberDictionaryElement(
JSObject* obj,
Object* receiver,
NumberDictionary* backing_store,
uint32_t index) {
int entry = backing_store->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
Object* element = backing_store->ValueAt(entry);
PropertyDetails details = backing_store->DetailsAt(entry);
if (details.type() == CALLBACKS) {
return obj->GetElementWithCallback(receiver,
element,
index,
obj);
} else {
return element;
}
}
return obj->GetHeap()->the_hole_value();
}
static MaybeObject* DeleteCommon(JSObject* obj, static MaybeObject* DeleteCommon(JSObject* obj,
uint32_t index, uint32_t key,
JSReceiver::DeleteMode mode) { JSReceiver::DeleteMode mode) {
Isolate* isolate = obj->GetIsolate(); Isolate* isolate = obj->GetIsolate();
Heap* heap = isolate->heap(); Heap* heap = isolate->heap();
@ -357,11 +406,11 @@ class DictionaryElementsAccessor
backing_store = FixedArray::cast(backing_store->get(1)); backing_store = FixedArray::cast(backing_store->get(1));
} }
NumberDictionary* dictionary = NumberDictionary::cast(backing_store); NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
int entry = dictionary->FindEntry(index); int entry = dictionary->FindEntry(key);
if (entry != NumberDictionary::kNotFound) { if (entry != NumberDictionary::kNotFound) {
Object* result = dictionary->DeleteProperty(entry, mode); Object* result = dictionary->DeleteProperty(entry, mode);
if (result == heap->true_value()) { if (result == heap->true_value()) {
MaybeObject* maybe_elements = dictionary->Shrink(index); MaybeObject* maybe_elements = dictionary->Shrink(key);
FixedArray* new_elements = NULL; FixedArray* new_elements = NULL;
if (!maybe_elements->To(&new_elements)) { if (!maybe_elements->To(&new_elements)) {
return maybe_elements; return maybe_elements;
@ -378,7 +427,7 @@ class DictionaryElementsAccessor
// throws an exception. // throws an exception.
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Object> holder(obj); Handle<Object> holder(obj);
Handle<Object> name = isolate->factory()->NewNumberFromUint(index); Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
Handle<Object> args[2] = { name, holder }; Handle<Object> args[2] = { name, holder };
Handle<Object> error = Handle<Object> error =
isolate->factory()->NewTypeError("strict_delete_property", isolate->factory()->NewTypeError("strict_delete_property",
@ -389,32 +438,40 @@ class DictionaryElementsAccessor
return heap->true_value(); return heap->true_value();
} }
protected:
friend class ElementsAccessorBase<DictionaryElementsAccessor,
NumberDictionary>;
virtual MaybeObject* Delete(JSObject* obj, virtual MaybeObject* Delete(JSObject* obj,
uint32_t index, uint32_t key,
JSReceiver::DeleteMode mode) { JSReceiver::DeleteMode mode) {
return DeleteCommon(obj, index, mode); return DeleteCommon(obj, key, mode);
}
virtual MaybeObject* GetWithReceiver(JSObject* obj,
Object* receiver,
uint32_t index) {
return GetNumberDictionaryElement(obj,
receiver,
obj->element_dictionary(),
index);
} }
static uint32_t GetCapacity(NumberDictionary* dict) { static MaybeObject* Get(NumberDictionary* backing_store,
return dict->Capacity(); uint32_t key,
JSObject* obj,
Object* receiver) {
int entry = backing_store->FindEntry(key);
if (entry != NumberDictionary::kNotFound) {
Object* element = backing_store->ValueAt(entry);
PropertyDetails details = backing_store->DetailsAt(entry);
if (details.type() == CALLBACKS) {
return obj->GetElementWithCallback(receiver,
element,
key,
obj);
} else {
return element;
}
}
return obj->GetHeap()->the_hole_value();
} }
static MaybeObject* GetElementAtCapacityIndex(NumberDictionary* dict, static uint32_t GetKeyForIndex(NumberDictionary* dict,
int index) { uint32_t index) {
if (dict->IsKey(dict->KeyAt(index))) { Object* key = dict->KeyAt(index);
return dict->ValueAt(index); return Smi::cast(key)->value();
} else {
return dict->GetHeap()->the_hole_value();
}
} }
}; };
@ -422,15 +479,16 @@ class DictionaryElementsAccessor
class NonStrictArgumentsElementsAccessor class NonStrictArgumentsElementsAccessor
: public ElementsAccessorBase<NonStrictArgumentsElementsAccessor, : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
FixedArray> { FixedArray> {
public: protected:
virtual MaybeObject* GetWithReceiver(JSObject* obj, friend class ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
Object* receiver, FixedArray>;
uint32_t index) {
FixedArray* parameter_map = FixedArray::cast(obj->elements()); static MaybeObject* Get(FixedArray* parameter_map,
uint32_t length = parameter_map->length(); uint32_t key,
Object* probe = JSObject* obj,
(index < length - 2) ? parameter_map->get(index + 2) : NULL; Object* receiver) {
if (probe != NULL && !probe->IsTheHole()) { Object* probe = GetParameterMapArg(parameter_map, key);
if (!probe->IsTheHole()) {
Context* context = Context::cast(parameter_map->get(0)); Context* context = Context::cast(parameter_map->get(0));
int context_index = Smi::cast(probe)->value(); int context_index = Smi::cast(probe)->value();
ASSERT(!context->get(context_index)->IsTheHole()); ASSERT(!context->get(context_index)->IsTheHole());
@ -438,56 +496,105 @@ class NonStrictArgumentsElementsAccessor
} else { } else {
// Object is not mapped, defer to the arguments. // Object is not mapped, defer to the arguments.
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) { return ElementsAccessor::ForArray(arguments)->Get(arguments,
return DictionaryElementsAccessor::GetNumberDictionaryElement( key,
obj, obj,
receiver, receiver);
NumberDictionary::cast(arguments),
index);
} else if (index < static_cast<uint32_t>(arguments->length())) {
return arguments->get(index);
}
} }
return obj->GetHeap()->the_hole_value();
} }
virtual MaybeObject* Delete(JSObject* obj, virtual MaybeObject* Delete(JSObject* obj,
uint32_t index, uint32_t key
,
JSReceiver::DeleteMode mode) { JSReceiver::DeleteMode mode) {
FixedArray* parameter_map = FixedArray::cast(obj->elements()); FixedArray* parameter_map = FixedArray::cast(obj->elements());
uint32_t length = parameter_map->length(); Object* probe = GetParameterMapArg(parameter_map, key);
Object* probe = if (!probe->IsTheHole()) {
index < (length - 2) ? parameter_map->get(index + 2) : NULL;
if (probe != NULL && !probe->IsTheHole()) {
// TODO(kmillikin): We could check if this was the last aliased // TODO(kmillikin): We could check if this was the last aliased
// parameter, and revert to normal elements in that case. That // parameter, and revert to normal elements in that case. That
// would enable GC of the context. // would enable GC of the context.
parameter_map->set_the_hole(index + 2); parameter_map->set_the_hole(key + 2);
} else { } else {
FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
if (arguments->IsDictionary()) { if (arguments->IsDictionary()) {
return DictionaryElementsAccessor::DeleteCommon(obj, index, mode); return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
} else { } else {
return FastElementsAccessor::DeleteCommon(obj, index); return FastElementsAccessor::DeleteCommon(obj, key);
} }
} }
return obj->GetHeap()->true_value(); return obj->GetHeap()->true_value();
} }
static uint32_t GetCapacity(FixedArray* obj) { static uint32_t GetCapacity(FixedArray* parameter_map) {
// TODO(danno): Return max of parameter map length or backing store FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
// capacity. return Max(static_cast<uint32_t>(parameter_map->length() - 2),
return 0; ForArray(arguments)->GetCapacity(arguments));
} }
static MaybeObject* GetElementAtCapacityIndex(FixedArray* obj, int index) { static uint32_t GetKeyForIndex(FixedArray* dict,
// TODO(danno): Return either value from parameter map of backing uint32_t index) {
// store value at index. return index;
return obj->GetHeap()->the_hole_value(); }
static bool HasElementAtIndex(FixedArray* parameter_map,
uint32_t index,
JSObject* holder,
Object* receiver) {
Object* probe = GetParameterMapArg(parameter_map, index);
if (!probe->IsTheHole()) {
return true;
} else {
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
return !accessor->Get(arguments, index, holder, receiver)->IsTheHole();
}
}
private:
static Object* GetParameterMapArg(FixedArray* parameter_map,
uint32_t key) {
uint32_t length = parameter_map->length();
return key < (length - 2 )
? parameter_map->get(key + 2)
: parameter_map->GetHeap()->the_hole_value();
} }
}; };
ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
switch (array->map()->instance_type()) {
case FIXED_ARRAY_TYPE:
if (array->IsDictionary()) {
return elements_accessors_[JSObject::DICTIONARY_ELEMENTS];
} else {
return elements_accessors_[JSObject::FAST_ELEMENTS];
}
case EXTERNAL_BYTE_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_BYTE_ELEMENTS];
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
case EXTERNAL_SHORT_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_SHORT_ELEMENTS];
case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
case EXTERNAL_INT_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_INT_ELEMENTS];
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS];
case EXTERNAL_FLOAT_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_FLOAT_ELEMENTS];
case EXTERNAL_DOUBLE_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_DOUBLE_ELEMENTS];
case EXTERNAL_PIXEL_ARRAY_TYPE:
return elements_accessors_[JSObject::EXTERNAL_PIXEL_ELEMENTS];
default:
UNREACHABLE();
return NULL;
break;
}
}
void ElementsAccessor::InitializeOncePerProcess() { void ElementsAccessor::InitializeOncePerProcess() {
static struct ConcreteElementsAccessors { static struct ConcreteElementsAccessors {
FastElementsAccessor fast_elements_handler; FastElementsAccessor fast_elements_handler;

38
deps/v8/src/elements.h

@ -39,16 +39,19 @@ class ElementsAccessor {
public: public:
ElementsAccessor() { } ElementsAccessor() { }
virtual ~ElementsAccessor() { } virtual ~ElementsAccessor() { }
virtual MaybeObject* GetWithReceiver(JSObject* obj, virtual MaybeObject* Get(FixedArrayBase* backing_store,
Object* receiver, uint32_t key,
uint32_t index) = 0; JSObject* holder,
Object* receiver) = 0;
virtual MaybeObject* Delete(JSObject* obj, virtual MaybeObject* Delete(JSObject* holder,
uint32_t index, uint32_t key,
JSReceiver::DeleteMode mode) = 0; JSReceiver::DeleteMode mode) = 0;
virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from, virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
FixedArray* to) = 0; FixedArray* to,
JSObject* holder,
Object* receiver) = 0;
// Returns a shared ElementsAccessor for the specified ElementsKind. // Returns a shared ElementsAccessor for the specified ElementsKind.
static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) { static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) {
@ -56,8 +59,31 @@ class ElementsAccessor {
return elements_accessors_[elements_kind]; return elements_accessors_[elements_kind];
} }
static ElementsAccessor* ForArray(FixedArrayBase* array);
static void InitializeOncePerProcess(); static void InitializeOncePerProcess();
protected:
friend class NonStrictArgumentsElementsAccessor;
virtual uint32_t GetCapacity(FixedArrayBase* backing_store) = 0;
virtual bool HasElementAtIndex(FixedArrayBase* backing_store,
uint32_t index,
JSObject* holder,
Object* receiver) = 0;
// Element handlers distinguish between indexes and keys when the manipulate
// elements. Indexes refer to elements in terms of their location in the
// underlying storage's backing store representation, and are between 0
// GetCapacity. Keys refer to elements in terms of the value that would be
// specific in JavaScript to access the element. In most implementations, keys
// are equivalent to indexes, and GetKeyForIndex returns the same value it is
// passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps the
// index to a key using the KeyAt method on the NumberDictionary.
virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
uint32_t index) = 0;
private: private:
static ElementsAccessor** elements_accessors_; static ElementsAccessor** elements_accessors_;

51
deps/v8/src/full-codegen.cc

@ -862,7 +862,7 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements()); VisitStatements(stmt->statements());
scope_ = saved_scope; scope_ = saved_scope;
__ bind(nested_statement.break_target()); __ bind(nested_statement.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
@ -932,8 +932,7 @@ void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
context_register()); context_register());
} }
Iteration* loop = current->AsIteration(); __ jmp(current->AsIteration()->continue_label());
__ jmp(loop->continue_target());
} }
@ -961,8 +960,7 @@ void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
context_register()); context_register());
} }
Breakable* target = current->AsBreakable(); __ jmp(current->AsBreakable()->break_label());
__ jmp(target->break_target());
} }
@ -1030,12 +1028,12 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
// Record the position of the do while condition and make sure it is // Record the position of the do while condition and make sure it is
// possible to break on the condition. // possible to break on the condition.
__ bind(loop_statement.continue_target()); __ bind(loop_statement.continue_label());
PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
SetExpressionPosition(stmt->cond(), stmt->condition_position()); SetExpressionPosition(stmt->cond(), stmt->condition_position());
VisitForControl(stmt->cond(), VisitForControl(stmt->cond(),
&stack_check, &stack_check,
loop_statement.break_target(), loop_statement.break_label(),
&stack_check); &stack_check);
// Check stack before looping. // Check stack before looping.
@ -1045,7 +1043,7 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
__ jmp(&body); __ jmp(&body);
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
__ bind(loop_statement.break_target()); __ bind(loop_statement.break_label());
decrement_loop_depth(); decrement_loop_depth();
} }
@ -1066,7 +1064,7 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
// Emit the statement position here as this is where the while // Emit the statement position here as this is where the while
// statement code starts. // statement code starts.
__ bind(loop_statement.continue_target()); __ bind(loop_statement.continue_label());
SetStatementPosition(stmt); SetStatementPosition(stmt);
// Check stack before looping. // Check stack before looping.
@ -1075,11 +1073,11 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
__ bind(&test); __ bind(&test);
VisitForControl(stmt->cond(), VisitForControl(stmt->cond(),
&body, &body,
loop_statement.break_target(), loop_statement.break_label(),
loop_statement.break_target()); loop_statement.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
__ bind(loop_statement.break_target()); __ bind(loop_statement.break_label());
decrement_loop_depth(); decrement_loop_depth();
} }
@ -1102,7 +1100,7 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
Visit(stmt->body()); Visit(stmt->body());
PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
__ bind(loop_statement.continue_target()); __ bind(loop_statement.continue_label());
SetStatementPosition(stmt); SetStatementPosition(stmt);
if (stmt->next() != NULL) { if (stmt->next() != NULL) {
Visit(stmt->next()); Visit(stmt->next());
@ -1119,14 +1117,14 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
if (stmt->cond() != NULL) { if (stmt->cond() != NULL) {
VisitForControl(stmt->cond(), VisitForControl(stmt->cond(),
&body, &body,
loop_statement.break_target(), loop_statement.break_label(),
loop_statement.break_target()); loop_statement.break_label());
} else { } else {
__ jmp(&body); __ jmp(&body);
} }
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
__ bind(loop_statement.break_target()); __ bind(loop_statement.break_label());
decrement_loop_depth(); decrement_loop_depth();
} }
@ -1144,7 +1142,7 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
// to introduce a new scope to bind the catch variable and to remove // to introduce a new scope to bind the catch variable and to remove
// that scope again afterwards. // that scope again afterwards.
Label try_handler_setup, catch_entry, done; Label try_handler_setup, done;
__ Call(&try_handler_setup); __ Call(&try_handler_setup);
// Try handler code, exception in result register. // Try handler code, exception in result register.
@ -1170,12 +1168,13 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
// Try block code. Sets up the exception handler chain. // Try block code. Sets up the exception handler chain.
__ bind(&try_handler_setup); __ bind(&try_handler_setup);
{ {
TryCatch try_block(this, &catch_entry); const int delta = StackHandlerConstants::kSize / kPointerSize;
TryCatch try_block(this);
__ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
increment_stack_height(StackHandlerConstants::kSize / kPointerSize); increment_stack_height(delta);
Visit(stmt->try_block()); Visit(stmt->try_block());
__ PopTryHandler(); __ PopTryHandler();
decrement_stack_height(StackHandlerConstants::kSize / kPointerSize); decrement_stack_height(delta);
} }
__ bind(&done); __ bind(&done);
} }
@ -1208,9 +1207,6 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
Label finally_entry; Label finally_entry;
Label try_handler_setup; Label try_handler_setup;
const int original_stack_height = stack_height(); const int original_stack_height = stack_height();
const int finally_block_stack_height = original_stack_height + 2;
const int try_block_stack_height = original_stack_height + 5;
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
// Setup the try-handler chain. Use a call to // Setup the try-handler chain. Use a call to
// Jump to try-handler setup and try-block code. Use call to put try-handler // Jump to try-handler setup and try-block code. Use call to put try-handler
@ -1219,9 +1215,9 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// Try handler code. Return address of call is pushed on handler stack. // Try handler code. Return address of call is pushed on handler stack.
{ {
// This code is only executed during stack-handler traversal when an // This code is only executed during stack-handler traversal when an
// exception is thrown. The execption is in the result register, which // exception is thrown. The exception is in the result register, which
// is retained by the finally block. // is retained by the finally block.
// Call the finally block and then rethrow the exception. // Call the finally block and then rethrow the exception if it returns.
__ Call(&finally_entry); __ Call(&finally_entry);
__ push(result_register()); __ push(result_register());
__ CallRuntime(Runtime::kReThrow, 1); __ CallRuntime(Runtime::kReThrow, 1);
@ -1232,7 +1228,7 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// Finally block implementation. // Finally block implementation.
Finally finally_block(this); Finally finally_block(this);
EnterFinallyBlock(); EnterFinallyBlock();
set_stack_height(finally_block_stack_height); set_stack_height(original_stack_height + Finally::kElementCount);
Visit(stmt->finally_block()); Visit(stmt->finally_block());
ExitFinallyBlock(); // Return to the calling code. ExitFinallyBlock(); // Return to the calling code.
} }
@ -1240,9 +1236,10 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
__ bind(&try_handler_setup); __ bind(&try_handler_setup);
{ {
// Setup try handler (stack pointer registers). // Setup try handler (stack pointer registers).
const int delta = StackHandlerConstants::kSize / kPointerSize;
TryFinally try_block(this, &finally_entry); TryFinally try_block(this, &finally_entry);
__ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
set_stack_height(try_block_stack_height); set_stack_height(original_stack_height + delta);
Visit(stmt->try_block()); Visit(stmt->try_block());
__ PopTryHandler(); __ PopTryHandler();
set_stack_height(original_stack_height); set_stack_height(original_stack_height);

113
deps/v8/src/full-codegen.h

@ -111,10 +111,7 @@ class FullCodeGenerator: public AstVisitor {
private: private:
class Breakable; class Breakable;
class Iteration; class Iteration;
class TryCatch;
class TryFinally;
class Finally;
class ForIn;
class TestContext; class TestContext;
class NestedStatement BASE_EMBEDDED { class NestedStatement BASE_EMBEDDED {
@ -132,10 +129,6 @@ class FullCodeGenerator: public AstVisitor {
virtual Breakable* AsBreakable() { return NULL; } virtual Breakable* AsBreakable() { return NULL; }
virtual Iteration* AsIteration() { return NULL; } virtual Iteration* AsIteration() { return NULL; }
virtual TryCatch* AsTryCatch() { return NULL; }
virtual TryFinally* AsTryFinally() { return NULL; }
virtual Finally* AsFinally() { return NULL; }
virtual ForIn* AsForIn() { return NULL; }
virtual bool IsContinueTarget(Statement* target) { return false; } virtual bool IsContinueTarget(Statement* target) { return false; }
virtual bool IsBreakTarget(Statement* target) { return false; } virtual bool IsBreakTarget(Statement* target) { return false; }
@ -158,110 +151,102 @@ class FullCodeGenerator: public AstVisitor {
DISALLOW_COPY_AND_ASSIGN(NestedStatement); DISALLOW_COPY_AND_ASSIGN(NestedStatement);
}; };
// A breakable statement such as a block.
class Breakable : public NestedStatement { class Breakable : public NestedStatement {
public: public:
Breakable(FullCodeGenerator* codegen, Breakable(FullCodeGenerator* codegen, BreakableStatement* statement)
BreakableStatement* break_target) : NestedStatement(codegen), statement_(statement) {
: NestedStatement(codegen), }
target_(break_target) {}
virtual ~Breakable() {} virtual ~Breakable() {}
virtual Breakable* AsBreakable() { return this; } virtual Breakable* AsBreakable() { return this; }
virtual bool IsBreakTarget(Statement* statement) { virtual bool IsBreakTarget(Statement* target) {
return target_ == statement; return statement() == target;
} }
BreakableStatement* statement() { return target_; }
Label* break_target() { return &break_target_label_; } BreakableStatement* statement() { return statement_; }
Label* break_label() { return &break_label_; }
private: private:
BreakableStatement* target_; BreakableStatement* statement_;
Label break_target_label_; Label break_label_;
DISALLOW_COPY_AND_ASSIGN(Breakable);
}; };
// An iteration statement such as a while, for, or do loop.
class Iteration : public Breakable { class Iteration : public Breakable {
public: public:
Iteration(FullCodeGenerator* codegen, Iteration(FullCodeGenerator* codegen, IterationStatement* statement)
IterationStatement* iteration_statement) : Breakable(codegen, statement) {
: Breakable(codegen, iteration_statement) {} }
virtual ~Iteration() {} virtual ~Iteration() {}
virtual Iteration* AsIteration() { return this; } virtual Iteration* AsIteration() { return this; }
virtual bool IsContinueTarget(Statement* statement) { virtual bool IsContinueTarget(Statement* target) {
return this->statement() == statement; return statement() == target;
} }
Label* continue_target() { return &continue_target_label_; }
Label* continue_label() { return &continue_label_; }
private: private:
Label continue_target_label_; Label continue_label_;
DISALLOW_COPY_AND_ASSIGN(Iteration);
}; };
// The environment inside the try block of a try/catch statement. // The try block of a try/catch statement.
class TryCatch : public NestedStatement { class TryCatch : public NestedStatement {
public: public:
explicit TryCatch(FullCodeGenerator* codegen, Label* catch_entry) explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {
: NestedStatement(codegen), catch_entry_(catch_entry) { } }
virtual ~TryCatch() {} virtual ~TryCatch() {}
virtual TryCatch* AsTryCatch() { return this; }
Label* catch_entry() { return catch_entry_; }
virtual NestedStatement* Exit(int* stack_depth, int* context_length); virtual NestedStatement* Exit(int* stack_depth, int* context_length);
private:
Label* catch_entry_;
DISALLOW_COPY_AND_ASSIGN(TryCatch);
}; };
// The environment inside the try block of a try/finally statement. // The try block of a try/finally statement.
class TryFinally : public NestedStatement { class TryFinally : public NestedStatement {
public: public:
explicit TryFinally(FullCodeGenerator* codegen, Label* finally_entry) TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
: NestedStatement(codegen), finally_entry_(finally_entry) { } : NestedStatement(codegen), finally_entry_(finally_entry) {
}
virtual ~TryFinally() {} virtual ~TryFinally() {}
virtual TryFinally* AsTryFinally() { return this; }
Label* finally_entry() { return finally_entry_; }
virtual NestedStatement* Exit(int* stack_depth, int* context_length); virtual NestedStatement* Exit(int* stack_depth, int* context_length);
private: private:
Label* finally_entry_; Label* finally_entry_;
DISALLOW_COPY_AND_ASSIGN(TryFinally);
}; };
// A FinallyEnvironment represents being inside a finally block. // The finally block of a try/finally statement.
// Abnormal termination of the finally block needs to clean up
// the block's parameters from the stack.
class Finally : public NestedStatement { class Finally : public NestedStatement {
public: public:
static const int kElementCount = 2;
explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { } explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
virtual ~Finally() {} virtual ~Finally() {}
virtual Finally* AsFinally() { return this; }
virtual NestedStatement* Exit(int* stack_depth, int* context_length) { virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
*stack_depth += kFinallyStackElementCount; *stack_depth += kElementCount;
return previous_; return previous_;
} }
private:
// Number of extra stack slots occupied during a finally block.
static const int kFinallyStackElementCount = 2;
DISALLOW_COPY_AND_ASSIGN(Finally);
}; };
// A ForInEnvironment represents being inside a for-in loop. // The body of a for/in loop.
// Abnormal termination of the for-in block needs to clean up
// the block's temporary storage from the stack.
class ForIn : public Iteration { class ForIn : public Iteration {
public: public:
ForIn(FullCodeGenerator* codegen, static const int kElementCount = 5;
ForInStatement* statement)
: Iteration(codegen, statement) { } ForIn(FullCodeGenerator* codegen, ForInStatement* statement)
: Iteration(codegen, statement) {
}
virtual ~ForIn() {} virtual ~ForIn() {}
virtual ForIn* AsForIn() { return this; }
virtual NestedStatement* Exit(int* stack_depth, int* context_length) { virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
*stack_depth += kForInStackElementCount; *stack_depth += kElementCount;
return previous_; return previous_;
} }
private:
static const int kForInStackElementCount = 5;
DISALLOW_COPY_AND_ASSIGN(ForIn);
}; };
// A WithOrCatch represents being inside the body of a with or catch // The body of a with or catch.
// statement. Exiting the body needs to remove a link from the context
// chain.
class WithOrCatch : public NestedStatement { class WithOrCatch : public NestedStatement {
public: public:
explicit WithOrCatch(FullCodeGenerator* codegen) explicit WithOrCatch(FullCodeGenerator* codegen)

17
deps/v8/src/ia32/full-codegen-ia32.cc

@ -875,7 +875,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
__ bind(&next_test); __ bind(&next_test);
__ Drop(1); // Switch value is no longer needed. __ Drop(1); // Switch value is no longer needed.
if (default_clause == NULL) { if (default_clause == NULL) {
__ jmp(nested_statement.break_target()); __ jmp(nested_statement.break_label());
} else { } else {
__ jmp(default_clause->body_target()); __ jmp(default_clause->body_target());
} }
@ -890,7 +890,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
VisitStatements(clause->statements()); VisitStatements(clause->statements());
} }
__ bind(nested_statement.break_target()); __ bind(nested_statement.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
@ -1006,12 +1006,13 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(eax); // Fixed array length (as smi). __ push(eax); // Fixed array length (as smi).
__ push(Immediate(Smi::FromInt(0))); // Initial index. __ push(Immediate(Smi::FromInt(0))); // Initial index.
increment_stack_height(4); // 1 ~ The object has already been pushed.
increment_stack_height(ForIn::kElementCount - 1);
// Generate code for doing the condition check. // Generate code for doing the condition check.
__ bind(&loop); __ bind(&loop);
__ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
__ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
__ j(above_equal, loop_statement.break_target()); __ j(above_equal, loop_statement.break_label());
// Get the current entry of the array into register ebx. // Get the current entry of the array into register ebx.
__ mov(ebx, Operand(esp, 2 * kPointerSize)); __ mov(ebx, Operand(esp, 2 * kPointerSize));
@ -1035,7 +1036,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(ebx); // Current entry. __ push(ebx); // Current entry.
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
__ test(eax, Operand(eax)); __ test(eax, Operand(eax));
__ j(equal, loop_statement.continue_target()); __ j(equal, loop_statement.continue_label());
__ mov(ebx, Operand(eax)); __ mov(ebx, Operand(eax));
// Update the 'each' property or variable from the possibly filtered // Update the 'each' property or variable from the possibly filtered
@ -1052,17 +1053,17 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for going to the next element by incrementing the // Generate code for going to the next element by incrementing the
// index (smi) stored on top of the stack. // index (smi) stored on top of the stack.
__ bind(loop_statement.continue_target()); __ bind(loop_statement.continue_label());
__ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
EmitStackCheck(stmt); EmitStackCheck(stmt);
__ jmp(&loop); __ jmp(&loop);
// Remove the pointers stored on the stack. // Remove the pointers stored on the stack.
__ bind(loop_statement.break_target()); __ bind(loop_statement.break_label());
__ add(Operand(esp), Immediate(5 * kPointerSize)); __ add(Operand(esp), Immediate(5 * kPointerSize));
decrement_stack_height(5); decrement_stack_height(ForIn::kElementCount);
// Exit and decrement the loop depth. // Exit and decrement the loop depth.
__ bind(&exit); __ bind(&exit);
decrement_loop_depth(); decrement_loop_depth();

2
deps/v8/src/ia32/macro-assembler-ia32.cc

@ -69,8 +69,8 @@ void MacroAssembler::RecordWriteHelper(Register object,
// Compute number of region covering addr. See Page::GetRegionNumberForAddress // Compute number of region covering addr. See Page::GetRegionNumberForAddress
// method for more details. // method for more details.
and_(addr, Page::kPageAlignmentMask);
shr(addr, Page::kRegionSizeLog2); shr(addr, Page::kRegionSizeLog2);
and_(addr, Page::kPageAlignmentMask >> Page::kRegionSizeLog2);
// Set dirty mark for region. // Set dirty mark for region.
// Bit tests with a memory operand should be avoided on Intel processors, // Bit tests with a memory operand should be avoided on Intel processors,

6
deps/v8/src/isolate.cc

@ -1335,6 +1335,7 @@ void Isolate::ThreadDataTable::Remove(PerIsolateThreadData* data) {
if (list_ == data) list_ = data->next_; if (list_ == data) list_ = data->next_;
if (data->next_ != NULL) data->next_->prev_ = data->prev_; if (data->next_ != NULL) data->next_->prev_ = data->prev_;
if (data->prev_ != NULL) data->prev_->next_ = data->next_; if (data->prev_ != NULL) data->prev_->next_ = data->next_;
delete data;
} }
@ -1536,6 +1537,9 @@ Isolate::~Isolate() {
// Has to be called while counters_ are still alive. // Has to be called while counters_ are still alive.
zone_.DeleteKeptSegment(); zone_.DeleteKeptSegment();
delete[] assembler_spare_buffer_;
assembler_spare_buffer_ = NULL;
delete unicode_cache_; delete unicode_cache_;
unicode_cache_ = NULL; unicode_cache_ = NULL;
@ -1569,6 +1573,8 @@ Isolate::~Isolate() {
handle_scope_implementer_ = NULL; handle_scope_implementer_ = NULL;
delete break_access_; delete break_access_;
break_access_ = NULL; break_access_ = NULL;
delete debugger_access_;
debugger_access_ = NULL;
delete compilation_cache_; delete compilation_cache_;
compilation_cache_ = NULL; compilation_cache_ = NULL;

52
deps/v8/src/messages.js

@ -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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -57,7 +57,7 @@ function FormatString(format, message) {
for (var i = 0; i < format.length; i++) { for (var i = 0; i < format.length; i++) {
var str = format[i]; var str = format[i];
for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) { for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) {
if (format[i] !== kReplacementMarkers[arg_num]) continue; if (str !== kReplacementMarkers[arg_num]) continue;
try { try {
str = ToDetailString(args[arg_num]); str = ToDetailString(args[arg_num]);
} catch (e) { } catch (e) {
@ -100,7 +100,8 @@ function ToStringCheckErrorObject(obj) {
function ToDetailString(obj) { function ToDetailString(obj) {
if (obj != null && IS_OBJECT(obj) && obj.toString === $Object.prototype.toString) { if (obj != null && IS_OBJECT(obj) &&
obj.toString === $Object.prototype.toString) {
var constructor = obj.constructor; var constructor = obj.constructor;
if (!constructor) return ToStringCheckErrorObject(obj); if (!constructor) return ToStringCheckErrorObject(obj);
var constructorName = constructor.name; var constructorName = constructor.name;
@ -207,7 +208,7 @@ function FormatMessage(message) {
stack_overflow: ["Maximum call stack size exceeded"], stack_overflow: ["Maximum call stack size exceeded"],
// SyntaxError // SyntaxError
unable_to_parse: ["Parse error"], unable_to_parse: ["Parse error"],
duplicate_regexp_flag: ["Duplicate RegExp flag ", "%0"], invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"],
illegal_break: ["Illegal break statement"], illegal_break: ["Illegal break statement"],
illegal_continue: ["Illegal continue statement"], illegal_continue: ["Illegal continue statement"],
@ -560,6 +561,7 @@ function SourceLocation(script, position, line, column, start, end) {
this.end = end; this.end = end;
} }
SourceLocation.prototype.__proto__ = null;
const kLineLengthLimit = 78; const kLineLengthLimit = 78;
@ -649,6 +651,7 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) {
this.to_position = to_position; this.to_position = to_position;
} }
SourceSlice.prototype.__proto__ = null;
/** /**
* Get the source text for a SourceSlice * Get the source text for a SourceSlice
@ -716,23 +719,28 @@ function CallSite(receiver, fun, pos) {
this.pos = pos; this.pos = pos;
} }
CallSite.prototype.__proto__ = null;
CallSite.prototype.getThis = function () { CallSite.prototype.getThis = function () {
return this.receiver; return this.receiver;
}; };
CallSite.prototype.getTypeName = function () { CallSite.prototype.getTypeName = function () {
var constructor = this.receiver.constructor; var constructor = this.receiver.constructor;
if (!constructor) if (!constructor) {
return %_CallFunction(this.receiver, ObjectToString); return %_CallFunction(this.receiver, ObjectToString);
}
var constructorName = constructor.name; var constructorName = constructor.name;
if (!constructorName) if (!constructorName) {
return %_CallFunction(this.receiver, ObjectToString); return %_CallFunction(this.receiver, ObjectToString);
}
return constructorName; return constructorName;
}; };
CallSite.prototype.isToplevel = function () { CallSite.prototype.isToplevel = function () {
if (this.receiver == null) if (this.receiver == null) {
return true; return true;
}
return IS_GLOBAL(this.receiver); return IS_GLOBAL(this.receiver);
}; };
@ -765,8 +773,9 @@ CallSite.prototype.getFunctionName = function () {
} }
// Maybe this is an evaluation? // Maybe this is an evaluation?
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
if (script && script.compilation_type == COMPILATION_TYPE_EVAL) if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
return "eval"; return "eval";
}
return null; return null;
}; };
@ -788,13 +797,15 @@ CallSite.prototype.getMethodName = function () {
this.receiver.__lookupSetter__(prop) === this.fun || this.receiver.__lookupSetter__(prop) === this.fun ||
(!this.receiver.__lookupGetter__(prop) && this.receiver[prop] === this.fun)) { (!this.receiver.__lookupGetter__(prop) && this.receiver[prop] === this.fun)) {
// If we find more than one match bail out to avoid confusion. // If we find more than one match bail out to avoid confusion.
if (name) if (name) {
return null; return null;
}
name = prop; name = prop;
} }
} }
if (name) if (name) {
return name; return name;
}
return null; return null;
}; };
@ -804,8 +815,9 @@ CallSite.prototype.getFileName = function () {
}; };
CallSite.prototype.getLineNumber = function () { CallSite.prototype.getLineNumber = function () {
if (this.pos == -1) if (this.pos == -1) {
return null; return null;
}
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
var location = null; var location = null;
if (script) { if (script) {
@ -815,8 +827,9 @@ CallSite.prototype.getLineNumber = function () {
}; };
CallSite.prototype.getColumnNumber = function () { CallSite.prototype.getColumnNumber = function () {
if (this.pos == -1) if (this.pos == -1) {
return null; return null;
}
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
var location = null; var location = null;
if (script) { if (script) {
@ -836,15 +849,17 @@ CallSite.prototype.getPosition = function () {
CallSite.prototype.isConstructor = function () { CallSite.prototype.isConstructor = function () {
var constructor = this.receiver ? this.receiver.constructor : null; var constructor = this.receiver ? this.receiver.constructor : null;
if (!constructor) if (!constructor) {
return false; return false;
}
return this.fun === constructor; return this.fun === constructor;
}; };
function FormatEvalOrigin(script) { function FormatEvalOrigin(script) {
var sourceURL = script.nameOrSourceURL(); var sourceURL = script.nameOrSourceURL();
if (sourceURL) if (sourceURL) {
return sourceURL; return sourceURL;
}
var eval_origin = "eval at "; var eval_origin = "eval at ";
if (script.eval_from_function_name) { if (script.eval_from_function_name) {
@ -1042,8 +1057,9 @@ function DefineError(f) {
function captureStackTrace(obj, cons_opt) { function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit; var stackTraceLimit = $Error.stackTraceLimit;
if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
if (stackTraceLimit < 0 || stackTraceLimit > 10000) if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
stackTraceLimit = 10000; stackTraceLimit = 10000;
}
var raw_stack = %CollectStackTrace(cons_opt var raw_stack = %CollectStackTrace(cons_opt
? cons_opt ? cons_opt
: captureStackTrace, stackTraceLimit); : captureStackTrace, stackTraceLimit);
@ -1117,8 +1133,10 @@ function errorToString() {
} catch(e) { } catch(e) {
// If this error message was encountered already return the empty // If this error message was encountered already return the empty
// string for it instead of recursively formatting it. // string for it instead of recursively formatting it.
if (isCyclicErrorMarker(e)) return ''; if (isCyclicErrorMarker(e)) {
else throw e; return '';
}
throw e;
} }
} }

18
deps/v8/src/mips/full-codegen-mips.cc

@ -747,9 +747,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ li(a2, Operand(variable->name())); __ li(a2, Operand(variable->name()));
// Declaration nodes are always introduced in one of two modes. // Declaration nodes are always introduced in one of two modes.
ASSERT(mode == Variable::VAR || ASSERT(mode == Variable::VAR ||
mode == Variable::CONST); mode == Variable::CONST ||
PropertyAttributes attr = mode == Variable::LET);
(mode == Variable::VAR) ? NONE : READ_ONLY; PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
__ li(a1, Operand(Smi::FromInt(attr))); __ li(a1, Operand(Smi::FromInt(attr)));
// Push initial value, if any. // Push initial value, if any.
// Note: For variables we must not push an initial value (such as // Note: For variables we must not push an initial value (such as
@ -886,7 +886,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
__ bind(&next_test); __ bind(&next_test);
__ Drop(1); // Switch value is no longer needed. __ Drop(1); // Switch value is no longer needed.
if (default_clause == NULL) { if (default_clause == NULL) {
__ Branch(nested_statement.break_target()); __ Branch(nested_statement.break_label());
} else { } else {
__ Branch(default_clause->body_target()); __ Branch(default_clause->body_target());
} }
@ -900,7 +900,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
VisitStatements(clause->statements()); VisitStatements(clause->statements());
} }
__ bind(nested_statement.break_target()); __ bind(nested_statement.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
@ -1026,7 +1026,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Load the current count to a0, load the length to a1. // Load the current count to a0, load the length to a1.
__ lw(a0, MemOperand(sp, 0 * kPointerSize)); __ lw(a0, MemOperand(sp, 0 * kPointerSize));
__ lw(a1, MemOperand(sp, 1 * kPointerSize)); __ lw(a1, MemOperand(sp, 1 * kPointerSize));
__ Branch(loop_statement.break_target(), hs, a0, Operand(a1)); __ Branch(loop_statement.break_label(), hs, a0, Operand(a1));
// Get the current entry of the array into register a3. // Get the current entry of the array into register a3.
__ lw(a2, MemOperand(sp, 2 * kPointerSize)); __ lw(a2, MemOperand(sp, 2 * kPointerSize));
@ -1053,7 +1053,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(a3); // Current entry. __ push(a3); // Current entry.
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
__ mov(a3, result_register()); __ mov(a3, result_register());
__ Branch(loop_statement.continue_target(), eq, a3, Operand(zero_reg)); __ Branch(loop_statement.continue_label(), eq, a3, Operand(zero_reg));
// Update the 'each' property or variable from the possibly filtered // Update the 'each' property or variable from the possibly filtered
// entry in register a3. // entry in register a3.
@ -1069,7 +1069,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for the going to the next element by incrementing // Generate code for the going to the next element by incrementing
// the index (smi) stored on top of the stack. // the index (smi) stored on top of the stack.
__ bind(loop_statement.continue_target()); __ bind(loop_statement.continue_label());
__ pop(a0); __ pop(a0);
__ Addu(a0, a0, Operand(Smi::FromInt(1))); __ Addu(a0, a0, Operand(Smi::FromInt(1)));
__ push(a0); __ push(a0);
@ -1078,7 +1078,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ Branch(&loop); __ Branch(&loop);
// Remove the pointers stored on the stack. // Remove the pointers stored on the stack.
__ bind(loop_statement.break_target()); __ bind(loop_statement.break_label());
__ Drop(5); __ Drop(5);
// Exit and decrement the loop depth. // Exit and decrement the loop depth.

82
deps/v8/src/objects.cc

@ -656,10 +656,11 @@ MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
} }
if (js_object->elements() != heap->empty_fixed_array()) { if (js_object->elements() != heap->empty_fixed_array()) {
MaybeObject* result = js_object->GetElementsAccessor()->GetWithReceiver( MaybeObject* result = js_object->GetElementsAccessor()->Get(
js_object->elements(),
index,
js_object, js_object,
receiver, receiver);
index);
if (result != heap->the_hole_value()) return result; if (result != heap->the_hole_value()) return result;
} }
} }
@ -4466,20 +4467,6 @@ void CodeCacheHashTable::RemoveByIndex(int index) {
} }
static bool HasKey(FixedArray* array, Object* key) {
int len0 = array->length();
for (int i = 0; i < len0; i++) {
Object* element = array->get(i);
if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
if (element->IsString() &&
key->IsString() && String::cast(element)->Equals(String::cast(key))) {
return true;
}
}
return false;
}
MaybeObject* PolymorphicCodeCache::Update(MapList* maps, MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
Code::Flags flags, Code::Flags flags,
Code* code) { Code* code) {
@ -4641,7 +4628,7 @@ MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
ElementsAccessor* accessor = array->GetElementsAccessor(); ElementsAccessor* accessor = array->GetElementsAccessor();
MaybeObject* maybe_result = MaybeObject* maybe_result =
accessor->AddElementsToFixedArray(array->elements(), this); accessor->AddElementsToFixedArray(array->elements(), this, array, array);
FixedArray* result; FixedArray* result;
if (!maybe_result->To<FixedArray>(&result)) return maybe_result; if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
#ifdef DEBUG #ifdef DEBUG
@ -4657,55 +4644,19 @@ MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
int len0 = length(); ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
MaybeObject* maybe_result =
accessor->AddElementsToFixedArray(other, this, NULL, NULL);
FixedArray* result;
if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
#ifdef DEBUG #ifdef DEBUG
if (FLAG_enable_slow_asserts) { if (FLAG_enable_slow_asserts) {
for (int i = 0; i < len0; i++) { for (int i = 0; i < result->length(); i++) {
ASSERT(get(i)->IsString() || get(i)->IsNumber()); Object* current = result->get(i);
ASSERT(current->IsNumber() || current->IsString());
} }
} }
#endif #endif
int len1 = other->length();
// Optimize if 'other' is empty.
// We cannot optimize if 'this' is empty, as other may have holes
// or non keys.
if (len1 == 0) return this;
// Compute how many elements are not in this.
int extra = 0;
for (int y = 0; y < len1; y++) {
Object* value = other->get(y);
if (!value->IsTheHole() && !HasKey(this, value)) extra++;
}
if (extra == 0) return this;
// Allocate the result
Object* obj;
{ MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
// Fill in the content
AssertNoAllocation no_gc;
FixedArray* result = FixedArray::cast(obj);
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
for (int i = 0; i < len0; i++) {
Object* e = get(i);
ASSERT(e->IsString() || e->IsNumber());
result->set(i, e, mode);
}
// Fill in the extra keys.
int index = 0;
for (int y = 0; y < len1; y++) {
Object* value = other->get(y);
if (!value->IsTheHole() && !HasKey(this, value)) {
Object* e = other->get(y);
ASSERT(e->IsString() || e->IsNumber());
result->set(len0 + index, e, mode);
index++;
}
}
ASSERT(extra == index);
return result; return result;
} }
@ -8718,9 +8669,10 @@ MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
Heap* heap = holder_handle->GetHeap(); Heap* heap = holder_handle->GetHeap();
ElementsAccessor* handler = holder_handle->GetElementsAccessor(); ElementsAccessor* handler = holder_handle->GetElementsAccessor();
MaybeObject* raw_result = handler->GetWithReceiver(*holder_handle, MaybeObject* raw_result = handler->Get(holder_handle->elements(),
*this_handle, index,
index); *holder_handle,
*this_handle);
if (raw_result != heap->the_hole_value()) return raw_result; if (raw_result != heap->the_hole_value()) return raw_result;
RETURN_IF_SCHEDULED_EXCEPTION(isolate); RETURN_IF_SCHEDULED_EXCEPTION(isolate);

15
deps/v8/src/regexp.js

@ -50,24 +50,29 @@ function DoConstructRegExp(object, pattern, flags) {
var global = false; var global = false;
var ignoreCase = false; var ignoreCase = false;
var multiline = false; var multiline = false;
for (var i = 0; i < flags.length; i++) { for (var i = 0; i < flags.length; i++) {
var c = %_CallFunction(flags, i, StringCharAt); var c = %_CallFunction(flags, i, StringCharAt);
switch (c) { switch (c) {
case 'g': case 'g':
// Allow duplicate flags to be consistent with JSC and others. if (global) {
throw MakeSyntaxError("invalid_regexp_flags", [flags]);
}
global = true; global = true;
break; break;
case 'i': case 'i':
if (ignoreCase) {
throw MakeSyntaxError("invalid_regexp_flags", [flags]);
}
ignoreCase = true; ignoreCase = true;
break; break;
case 'm': case 'm':
if (multiline) {
throw MakeSyntaxError("invalid_regexp_flags", [flags]);
}
multiline = true; multiline = true;
break; break;
default: default:
// Ignore flags that have no meaning to be consistent with throw MakeSyntaxError("invalid_regexp_flags", [flags]);
// JSC.
break;
} }
} }

93
deps/v8/src/scanner-base.cc

@ -41,12 +41,12 @@ Scanner::Scanner(UnicodeCache* unicode_cache)
: unicode_cache_(unicode_cache) { } : unicode_cache_(unicode_cache) { }
uc32 Scanner::ScanHexEscape(uc32 c, int length) { uc32 Scanner::ScanHexNumber(int expected_length) {
ASSERT(length <= 4); // prevent overflow ASSERT(expected_length <= 4); // prevent overflow
uc32 digits[4]; uc32 digits[4] = { 0, 0, 0, 0 };
uc32 x = 0; uc32 x = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < expected_length; i++) {
digits[i] = c0_; digits[i] = c0_;
int d = HexValue(c0_); int d = HexValue(c0_);
if (d < 0) { if (d < 0) {
@ -54,12 +54,11 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) {
// should be illegal, but other JS VMs just return the // should be illegal, but other JS VMs just return the
// non-escaped version of the original character. // non-escaped version of the original character.
// Push back digits read, except the last one (in c0_). // Push back digits that we have advanced past.
for (int j = i-1; j >= 0; j--) { for (int j = i-1; j >= 0; j--) {
PushBack(digits[j]); PushBack(digits[j]);
} }
// Notice: No handling of error - treat it as "\u"->"u". return -1;
return c;
} }
x = x * 16 + d; x = x * 16 + d;
Advance(); Advance();
@ -640,9 +639,17 @@ void JavaScriptScanner::ScanEscape() {
case 'n' : c = '\n'; break; case 'n' : c = '\n'; break;
case 'r' : c = '\r'; break; case 'r' : c = '\r'; break;
case 't' : c = '\t'; break; case 't' : c = '\t'; break;
case 'u' : c = ScanHexEscape(c, 4); break; case 'u' : {
c = ScanHexNumber(4);
if (c < 0) c = 'u';
break;
}
case 'v' : c = '\v'; break; case 'v' : c = '\v'; break;
case 'x' : c = ScanHexEscape(c, 2); break; case 'x' : {
c = ScanHexNumber(2);
if (c < 0) c = 'x';
break;
}
case '0' : // fall through case '0' : // fall through
case '1' : // fall through case '1' : // fall through
case '2' : // fall through case '2' : // fall through
@ -802,13 +809,11 @@ Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() { uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
Advance(); Advance();
if (c0_ != 'u') return unibrow::Utf8::kBadChar; if (c0_ != 'u') return -1;
Advance(); Advance();
uc32 c = ScanHexEscape('u', 4); uc32 result = ScanHexNumber(4);
// We do not allow a unicode escape sequence to start another if (result < 0) PushBack('u');
// unicode escape sequence. return result;
if (c == '\\') return unibrow::Utf8::kBadChar;
return c;
} }
@ -926,7 +931,11 @@ Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
if (c0_ == '\\') { if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape(); uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier start characters. // Only allow legal identifier start characters.
if (!unicode_cache_->IsIdentifierStart(c)) return Token::ILLEGAL; if (c < 0 ||
c == '\\' || // No recursive escapes.
!unicode_cache_->IsIdentifierStart(c)) {
return Token::ILLEGAL;
}
AddLiteralChar(c); AddLiteralChar(c);
return ScanIdentifierSuffix(&literal); return ScanIdentifierSuffix(&literal);
} }
@ -966,7 +975,11 @@ Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) {
if (c0_ == '\\') { if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape(); uc32 c = ScanIdentifierUnicodeEscape();
// Only allow legal identifier part characters. // Only allow legal identifier part characters.
if (!unicode_cache_->IsIdentifierPart(c)) return Token::ILLEGAL; if (c < 0 ||
c == '\\' ||
!unicode_cache_->IsIdentifierPart(c)) {
return Token::ILLEGAL;
}
AddLiteralChar(c); AddLiteralChar(c);
} else { } else {
AddLiteralChar(c0_); AddLiteralChar(c0_);
@ -992,8 +1005,9 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
// the scanner should pass uninterpreted bodies to the RegExp // the scanner should pass uninterpreted bodies to the RegExp
// constructor. // constructor.
LiteralScope literal(this); LiteralScope literal(this);
if (seen_equal) if (seen_equal) {
AddLiteralChar('='); AddLiteralChar('=');
}
while (c0_ != '/' || in_character_class) { while (c0_ != '/' || in_character_class) {
if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false; if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
@ -1025,20 +1039,47 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
} }
bool JavaScriptScanner::ScanLiteralUnicodeEscape() {
ASSERT(c0_ == '\\');
uc32 chars_read[6] = {'\\', 'u', 0, 0, 0, 0};
Advance();
int i = 1;
if (c0_ == 'u') {
i++;
while (i < 6) {
Advance();
if (!IsHexDigit(c0_)) break;
chars_read[i] = c0_;
i++;
}
}
if (i < 6) {
// Incomplete escape. Undo all advances and return false.
while (i > 0) {
i--;
PushBack(chars_read[i]);
}
return false;
}
// Complete escape. Add all chars to current literal buffer.
for (int i = 0; i < 6; i++) {
AddLiteralChar(chars_read[i]);
}
return true;
}
bool JavaScriptScanner::ScanRegExpFlags() { bool JavaScriptScanner::ScanRegExpFlags() {
// Scan regular expression flags. // Scan regular expression flags.
LiteralScope literal(this); LiteralScope literal(this);
while (unicode_cache_->IsIdentifierPart(c0_)) { while (unicode_cache_->IsIdentifierPart(c0_)) {
if (c0_ == '\\') { if (c0_ != '\\') {
uc32 c = ScanIdentifierUnicodeEscape(); AddLiteralCharAdvance();
if (c != static_cast<uc32>(unibrow::Utf8::kBadChar)) { } else {
// We allow any escaped character, unlike the restriction on if (!ScanLiteralUnicodeEscape()) {
// IdentifierPart when it is used to build an IdentifierName. break;
AddLiteralChar(c);
continue;
} }
} }
AddLiteralCharAdvance();
} }
literal.Complete(); literal.Complete();

6
deps/v8/src/scanner-base.h

@ -419,7 +419,7 @@ class Scanner {
} }
} }
uc32 ScanHexEscape(uc32 c, int length); uc32 ScanHexNumber(int expected_length);
// Return the current source position. // Return the current source position.
int source_pos() { int source_pos() {
@ -537,6 +537,10 @@ class JavaScriptScanner : public Scanner {
// Decodes a unicode escape-sequence which is part of an identifier. // Decodes a unicode escape-sequence which is part of an identifier.
// If the escape sequence cannot be decoded the result is kBadChar. // If the escape sequence cannot be decoded the result is kBadChar.
uc32 ScanIdentifierUnicodeEscape(); 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. // Start position of the octal literal last scanned.
Location octal_pos_; Location octal_pos_;

1
deps/v8/src/spaces.h

@ -409,6 +409,7 @@ class Space : public Malloced {
class CodeRange { class CodeRange {
public: public:
explicit CodeRange(Isolate* isolate); explicit CodeRange(Isolate* isolate);
~CodeRange() { TearDown(); }
// Reserves a range of virtual memory, but does not commit any of it. // Reserves a range of virtual memory, but does not commit any of it.
// Can only be called once, at heap initialization time. // Can only be called once, at heap initialization time.

2
deps/v8/src/string.js

@ -914,6 +914,8 @@ function ReplaceResultBuilder(str) {
this.special_string = str; this.special_string = str;
} }
ReplaceResultBuilder.prototype.__proto__ = null;
ReplaceResultBuilder.prototype.add = function(str) { ReplaceResultBuilder.prototype.add = function(str) {
str = TO_STRING_INLINE(str); str = TO_STRING_INLINE(str);

30
deps/v8/src/v8natives.js

@ -462,6 +462,7 @@ function PropertyDescriptor() {
} }
PropertyDescriptor.prototype.__proto__ = null; PropertyDescriptor.prototype.__proto__ = null;
PropertyDescriptor.prototype.toString = function() { PropertyDescriptor.prototype.toString = function() {
return "[object PropertyDescriptor]"; return "[object PropertyDescriptor]";
}; };
@ -1015,24 +1016,27 @@ function ObjectDefineProperty(obj, p, attributes) {
} }
function GetOwnEnumerablePropertyNames(properties) {
var names = new InternalArray();
for (var key in properties) {
if (%HasLocalProperty(properties, key)) {
names.push(key);
}
}
return names;
}
// ES5 section 15.2.3.7. // ES5 section 15.2.3.7.
function ObjectDefineProperties(obj, properties) { function ObjectDefineProperties(obj, properties) {
if (!IS_SPEC_OBJECT(obj)) if (!IS_SPEC_OBJECT(obj))
throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
var props = ToObject(properties); var props = ToObject(properties);
var key_values = []; var names = GetOwnEnumerablePropertyNames(props);
for (var key in props) { for (var i = 0; i < names.length; i++) {
if (%HasLocalProperty(props, key)) { var name = names[i];
key_values.push(key); var desc = ToPropertyDescriptor(props[name]);
var value = props[key]; DefineOwnProperty(obj, name, desc, true);
var desc = ToPropertyDescriptor(value);
key_values.push(desc);
}
}
for (var i = 0; i < key_values.length; i += 2) {
var key = key_values[i];
var desc = key_values[i + 1];
DefineOwnProperty(obj, key, desc, true);
} }
return obj; return obj;
} }

4
deps/v8/src/v8threads.cc

@ -305,7 +305,9 @@ ThreadManager::ThreadManager()
ThreadManager::~ThreadManager() { ThreadManager::~ThreadManager() {
// TODO(isolates): Destroy mutexes. delete mutex_;
delete free_anchor_;
delete in_use_anchor_;
} }

2
deps/v8/src/version.cc

@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script. // cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 5 #define MINOR_VERSION 5
#define BUILD_NUMBER 6 #define BUILD_NUMBER 7
#define PATCH_LEVEL 0 #define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise. // Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.) // (Boolean macro values are not supported by all preprocessors.)

12
deps/v8/src/x64/full-codegen-x64.cc

@ -842,7 +842,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
__ bind(&next_test); __ bind(&next_test);
__ Drop(1); // Switch value is no longer needed. __ Drop(1); // Switch value is no longer needed.
if (default_clause == NULL) { if (default_clause == NULL) {
__ jmp(nested_statement.break_target()); __ jmp(nested_statement.break_label());
} else { } else {
__ jmp(default_clause->body_target()); __ jmp(default_clause->body_target());
} }
@ -856,7 +856,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
VisitStatements(clause->statements()); VisitStatements(clause->statements());
} }
__ bind(nested_statement.break_target()); __ bind(nested_statement.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
@ -982,7 +982,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ bind(&loop); __ bind(&loop);
__ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index. __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
__ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length. __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
__ j(above_equal, loop_statement.break_target()); __ j(above_equal, loop_statement.break_label());
// Get the current entry of the array into register rbx. // Get the current entry of the array into register rbx.
__ movq(rbx, Operand(rsp, 2 * kPointerSize)); __ movq(rbx, Operand(rsp, 2 * kPointerSize));
@ -1010,7 +1010,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ push(rbx); // Current entry. __ push(rbx); // Current entry.
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
__ Cmp(rax, Smi::FromInt(0)); __ Cmp(rax, Smi::FromInt(0));
__ j(equal, loop_statement.continue_target()); __ j(equal, loop_statement.continue_label());
__ movq(rbx, rax); __ movq(rbx, rax);
// Update the 'each' property or variable from the possibly filtered // Update the 'each' property or variable from the possibly filtered
@ -1027,14 +1027,14 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// Generate code for going to the next element by incrementing the // Generate code for going to the next element by incrementing the
// index (smi) stored on top of the stack. // index (smi) stored on top of the stack.
__ bind(loop_statement.continue_target()); __ bind(loop_statement.continue_label());
__ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1)); __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
EmitStackCheck(stmt); EmitStackCheck(stmt);
__ jmp(&loop); __ jmp(&loop);
// Remove the pointers stored on the stack. // Remove the pointers stored on the stack.
__ bind(loop_statement.break_target()); __ bind(loop_statement.break_label());
__ addq(rsp, Immediate(5 * kPointerSize)); __ addq(rsp, Immediate(5 * kPointerSize));
// Exit and decrement the loop depth. // Exit and decrement the loop depth.

46
deps/v8/test/cctest/test-api.cc

@ -3617,6 +3617,52 @@ THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
} }
Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
const AccessorInfo& info) {
// Force the list of returned keys to be stored in a Arguments object.
Local<Script> indexed_property_names_script = Script::Compile(v8_str(
"function f(w,x) {"
" return arguments;"
"}"
"keys = f(0, 1, 2, 3);"
"keys;"));
Local<Value> result = indexed_property_names_script->Run();
return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
}
static v8::Handle<Value> NonStrictIndexedPropertyGetter(
uint32_t index,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
if (index < 4) {
return v8::Handle<Value>(v8_num(index));
}
return v8::Handle<Value>();
}
// Make sure that the the interceptor code in the runtime properly handles
// merging property name lists for non-string arguments arrays.
THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
v8::HandleScope scope;
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
0,
0,
0,
NonStrictArgsIndexedPropertyEnumerator);
LocalContext context;
context->Global()->Set(v8_str("obj"), templ->NewInstance());
Local<Script> create_args_script =
Script::Compile(v8_str(
"var key_count = 0;"
"for (x in obj) {key_count++;} key_count;"));
Local<Value> result = create_args_script->Run();
CHECK_EQ(v8_num(4), result);
}
static v8::Handle<Value> IdentityIndexedPropertyGetter( static v8::Handle<Value> IdentityIndexedPropertyGetter(
uint32_t index, uint32_t index,
const AccessorInfo& info) { const AccessorInfo& info) {

54
deps/v8/test/mjsunit/regress/regress-1620.js

@ -0,0 +1,54 @@
// 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.
// Don't allow malformed unicode escape sequences in identifiers.
// In strings and regexps we currently allow malformed unicode escape
// sequences without throwing a SyntaxError. Instead "\u22gk" would
// treat the "\u" as an identity escape, and evaluate to "u22gk".
// Due to code sharing, we did the same in identifiers. This should
// no longer be the case.
// See: http://code.google.com/p/v8/issues/detail?id=1620
assertThrows("var \\u\\u\\u = 42;");
assertThrows("var \\u41 = 42;");
assertThrows("var \\u123 = 42;");
eval("var \\u1234 = 42;");
assertEquals(42, eval("\u1234"));
assertThrows("var uuu = 42; var x = \\u\\u\\u");
// Regressions introduced and fixed again while fixing the above.
// Handle 0xFFFD correctly (it's a valid value, and shouldn't be used
// to mark an error).
assertEquals(0xFFFD, "\uFFFD".charCodeAt(0));
// Handle unicode escapes in regexp flags correctly.
assertThrows("/x/g\\uim", SyntaxError);
assertThrows("/x/g\\u2im", SyntaxError);
assertThrows("/x/g\\u22im", SyntaxError);
assertThrows("/x/g\\u222im", SyntaxError);
assertThrows("/x/g\\\\u2222im", SyntaxError);

36
deps/v8/test/mjsunit/regress/regress-1625.js

@ -0,0 +1,36 @@
// 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.
// Test that overwriting Array.prototype.push does not make
// Object.defineProperties misbehave.
Array.prototype.push = 1;
var desc = {foo: {value: 10}, bar: {get: function() {return 42; }}};
var obj = {};
var x = Object.defineProperties(obj, desc);
assertEquals(x.foo, 10);
assertEquals(x.bar, 42);

128
deps/v8/test/mjsunit/regress/regress-219.js

@ -30,6 +30,10 @@
// We should now allow duplicates of flags. // We should now allow duplicates of flags.
// (See http://code.google.com/p/v8/issues/detail?id=219) // (See http://code.google.com/p/v8/issues/detail?id=219)
// This has been reversed by issue 1628, since other browsers have also
// tightened their syntax.
// (See http://code.google.com/p/v8/issues/detail?id=1628)
// Base tests: we recognize the basic flags // Base tests: we recognize the basic flags
function assertFlags(re, global, multiline, ignoreCase) { function assertFlags(re, global, multiline, ignoreCase) {
@ -53,124 +57,92 @@ assertFlags(re, true, true, true)
// Double i's // Double i's
re = /a/ii; assertThrows("/a/ii");
assertFlags(re, false, false, true)
re = /a/gii;
assertFlags(re, true, false, true)
re = /a/igi; assertThrows("/a/gii");
assertFlags(re, true, false, true)
re = /a/iig; assertThrows("/a/igi");
assertFlags(re, true, false, true)
re = /a/gimi; assertThrows("/a/iig");
assertFlags(re, true, true, true)
re = /a/giim; assertThrows("/a/gimi");
assertFlags(re, true, true, true)
re = /a/igim; assertThrows("/a/giim");
assertFlags(re, true, true, true)
assertThrows("/a/igim");
re = RegExp("a", "ii"); assertThrows(function(){ return RegExp("a", "ii"); })
assertFlags(re, false, false, true)
re = RegExp("a", "gii"); assertThrows(function(){ return RegExp("a", "gii"); })
assertFlags(re, true, false, true)
re = RegExp("a", "igi"); assertThrows(function(){ return RegExp("a", "igi"); })
assertFlags(re, true, false, true)
re = RegExp("a", "iig"); assertThrows(function(){ return RegExp("a", "iig"); })
assertFlags(re, true, false, true)
re = RegExp("a", "gimi"); assertThrows(function(){ return RegExp("a", "gimi"); })
assertFlags(re, true, true, true)
re = RegExp("a", "giim"); assertThrows(function(){ return RegExp("a", "giim"); })
assertFlags(re, true, true, true)
re = RegExp("a", "igim"); assertThrows(function(){ return RegExp("a", "igim"); })
assertFlags(re, true, true, true)
// Tripple i's // Tripple i's
re = /a/iii; assertThrows("/a/iii");
assertFlags(re, false, false, true)
re = /a/giii; assertThrows("/a/giii");
assertFlags(re, true, false, true)
re = /a/igii; assertThrows("/a/igii");
assertFlags(re, true, false, true)
re = /a/iigi; assertThrows("/a/iigi");
assertFlags(re, true, false, true)
re = /a/iiig; assertThrows("/a/iiig");
assertFlags(re, true, false, true)
re = /a/miiig;
assertFlags(re, true, true, true)
assertThrows("/a/miiig");
re = RegExp("a", "iii"); assertThrows(function(){ return RegExp("a", "iii"); })
assertFlags(re, false, false, true)
re = RegExp("a", "giii"); assertThrows(function(){ return RegExp("a", "giii"); })
assertFlags(re, true, false, true)
re = RegExp("a", "igii"); assertThrows(function(){ return RegExp("a", "igii"); })
assertFlags(re, true, false, true)
re = RegExp("a", "iigi"); assertThrows(function(){ return RegExp("a", "iigi"); })
assertFlags(re, true, false, true)
re = RegExp("a", "iiig"); assertThrows(function(){ return RegExp("a", "iiig"); })
assertFlags(re, true, false, true)
re = RegExp("a", "miiig"); assertThrows(function(){ return RegExp("a", "miiig"); })
assertFlags(re, true, true, true)
// Illegal flags - flags late in string. // Illegal flags - valid flags late in string.
re = /a/arglebargleglopglyf; assertThrows("/a/arglebargleglopglyf");
assertFlags(re, true, false, false)
re = /a/arglebargleglopglif; assertThrows("/a/arglebargleglopglif");
assertFlags(re, true, false, true)
re = /a/arglebargleglopglym; assertThrows("/a/arglebargleglopglym");
assertFlags(re, true, true, false)
re = /a/arglebargleglopglim; assertThrows("/a/arglebargleglopglim");
assertFlags(re, true, true, true)
// Case of flags still matters. // Case of flags still matters.
re = /a/gmi; var re = /a/gmi;
assertFlags(re, true, true, true) assertFlags(re, true, true, true)
re = /a/Gmi; assertThrows("/a/Gmi");
assertFlags(re, false, true, true)
re = /a/gMi; assertThrows("/a/gMi");
assertFlags(re, true, false, true)
re = /a/gmI; assertThrows("/a/gmI");
assertFlags(re, true, true, false)
re = /a/GMi; assertThrows("/a/GMi");
assertFlags(re, false, false, true)
re = /a/GmI; assertThrows("/a/GmI");
assertFlags(re, false, true, false)
re = /a/gMI; assertThrows("/a/gMI");
assertFlags(re, true, false, false)
re = /a/GMI; assertThrows("/a/GMI");
assertFlags(re, false, false, false)
// Unicode escape sequences are not interpreted.
assertThrows("/a/\\u0067");
assertThrows("/a/\\u0069");
assertThrows("/a/\\u006d");
assertThrows("/a/\\u006D");

57
deps/v8/test/mjsunit/regress/regress-87.js

@ -25,34 +25,29 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function testFlags(flagstring, global, ignoreCase, multiline) { // In Issue 87, we allowed unicode escape sequences in RegExp flags.
var text = "/x/"+flagstring; // However, according to ES5, they should not be interpreted, but passed
var re = eval(text); // verbatim to the RegExp constructor.
assertEquals(global, re.global, text + ".global"); // (On top of that, the original test was bugged and never tested anything).
assertEquals(ignoreCase, re.ignoreCase, text + ".ignoreCase"); // The behavior was changed in r8969 to not interpret escapes, but this
assertEquals(multiline, re.multiline, text + ".multiline"); // test didn't test that, and only failed when making invalid flag characters
} // an error too.
testFlags("", false, false, false); assertThrows("/x/\\u0067");
assertThrows("/x/\\u0069");
testFlags("\u0067", true, false, false); assertThrows("/x/\\u006d");
testFlags("\u0069", false, true, false) assertThrows("/x/\\u0067i");
assertThrows("/x/\\u0069m");
testFlags("\u006d", false, false, true); assertThrows("/x/\\u006dg");
testFlags("\u0068", false, false, false); assertThrows("/x/m\\u0067");
assertThrows("/x/g\\u0069");
testFlags("\u0020", false, false, false); assertThrows("/x/i\\u006d");
assertThrows("/x/m\\u0067i");
testFlags("\u0067g", true, false, false); assertThrows("/x/g\\u0069m");
assertThrows("/x/i\\u006dg");
testFlags("g\u0067", true, false, false);
assertThrows("/x/\\u0068");
testFlags("abc\u0067efg", true, false, false); assertThrows("/x/\\u0020");
testFlags("i\u0067", true, true, false);
testFlags("\u0067i", true, true, false);

5
deps/v8/test/mozilla/mozilla.status

@ -246,9 +246,8 @@ ecma_3/Number/15.7.4.7-1: FAIL_OK
ecma_3/Number/15.7.4.6-1: FAIL_OK ecma_3/Number/15.7.4.6-1: FAIL_OK
#:=== RegExp:=== #:=== RegExp:===
# To be compatible with JSC we silently ignore flags that do not make # We don't match the syntax error message of Mozilla for invalid
# sense. These tests expects us to throw exceptions. # RegExp flags.
ecma_3/RegExp/regress-57631: FAIL_OK
ecma_3/RegExp/15.10.4.1-6: FAIL_OK ecma_3/RegExp/15.10.4.1-6: FAIL_OK
# PCRE doesn't allow subpattern nesting deeper than 200, this tests # PCRE doesn't allow subpattern nesting deeper than 200, this tests

16
deps/v8/test/sputnik/sputnik.status

@ -56,15 +56,6 @@ S15.10.6.3_A1_T16: FAIL_OK
# errors, for compatibility. # errors, for compatibility.
S15.10.2.11_A1_T2: FAIL S15.10.2.11_A1_T2: FAIL
S15.10.2.11_A1_T3: FAIL S15.10.2.11_A1_T3: FAIL
S15.10.4.1_A5_T1: FAIL
S15.10.4.1_A5_T2: FAIL
S15.10.4.1_A5_T3: FAIL
S15.10.4.1_A5_T4: FAIL
S15.10.4.1_A5_T5: FAIL
S15.10.4.1_A5_T6: FAIL
S15.10.4.1_A5_T7: FAIL
S15.10.4.1_A5_T8: FAIL
S15.10.4.1_A5_T9: FAIL
# We are more lenient in which string character escapes we allow than # We are more lenient in which string character escapes we allow than
# the spec (7.8.4 p. 19) wants us to be. This is for compatibility. # the spec (7.8.4 p. 19) wants us to be. This is for compatibility.
@ -99,6 +90,13 @@ S7.8.4_A7.4_T1: FAIL_OK
S7.8.4_A4.3_T5: FAIL_OK S7.8.4_A4.3_T5: FAIL_OK
S7.8.4_A7.2_T5: FAIL_OK S7.8.4_A7.2_T5: FAIL_OK
# Sputnik expects unicode escape sequences in RegExp flags to be interpreted.
# The specification requires them to be passed uninterpreted to the RegExp
# constructor. We now implement that.
S7.8.5_A3.1_T7: FAIL_OK
S7.8.5_A3.1_T8: FAIL_OK
S7.8.5_A3.1_T9: FAIL_OK
# We allow some keywords to be used as identifiers. # We allow some keywords to be used as identifiers.
S7.5.3_A1.15: FAIL_OK S7.5.3_A1.15: FAIL_OK
S7.5.3_A1.18: FAIL_OK S7.5.3_A1.18: FAIL_OK

6
deps/v8/tools/gyp/v8.gyp

@ -144,7 +144,6 @@
'Debug': { 'Debug': {
'defines': [ 'defines': [
'DEBUG', 'DEBUG',
'_DEBUG',
'ENABLE_DISASSEMBLER', 'ENABLE_DISASSEMBLER',
'V8_ENABLE_CHECKS', 'V8_ENABLE_CHECKS',
'OBJECT_PRINT', 'OBJECT_PRINT',
@ -372,7 +371,10 @@
'<(INTERMEDIATE_DIR)/snapshot.cc', '<(INTERMEDIATE_DIR)/snapshot.cc',
], ],
'variables': { 'variables': {
'mksnapshot_flags': [], 'mksnapshot_flags': [
'--log-snapshot-positions',
'--logfile', '<(INTERMEDIATE_DIR)/snapshot.log',
],
}, },
'conditions': [ 'conditions': [
['v8_target_arch=="arm"', { ['v8_target_arch=="arm"', {

Loading…
Cancel
Save