Add new files missing in previous commit.
Review URL: http://codereview.chromium.org/6967005
git-svn-id: http://v8.googlecode.com/svn/trunk@7819 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/extensions/experimental/i18n-utils.cc b/src/extensions/experimental/i18n-utils.cc
new file mode 100644
index 0000000..a82c8eb
--- /dev/null
+++ b/src/extensions/experimental/i18n-utils.cc
@@ -0,0 +1,43 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "i18n-utils.h"
+
+#include <string.h>
+
+namespace v8 {
+namespace internal {
+
+// static
+void I18NUtils::StrNCopy(char* dest, int length, const char* src) {
+ if (!dest || !src) return;
+
+ strncpy(dest, src, length);
+ dest[length - 1] = '\0';
+}
+
+} } // namespace v8::internal
diff --git a/src/extensions/experimental/i18n-utils.h b/src/extensions/experimental/i18n-utils.h
new file mode 100644
index 0000000..7702708
--- /dev/null
+++ b/src/extensions/experimental/i18n-utils.h
@@ -0,0 +1,49 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_
+#define V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_
+
+namespace v8 {
+namespace internal {
+
+class I18NUtils {
+ public:
+ // Safe string copy. Null terminates the destination. Copies at most
+ // (length - 1) bytes.
+ // We can't use snprintf since it's not supported on all relevant platforms.
+ // We can't use OS::SNPrintF, it's only for internal code.
+ // TODO(cira): Find a way to use OS::SNPrintF instead.
+ static void StrNCopy(char* dest, int length, const char* src);
+
+ private:
+ I18NUtils() {}
+};
+
+} } // namespace v8::internal
+
+#endif // V8_EXTENSIONS_EXPERIMENTAL_I18N_UTILS_H_
diff --git a/src/extensions/experimental/language-matcher.cc b/src/extensions/experimental/language-matcher.cc
new file mode 100644
index 0000000..385ebff
--- /dev/null
+++ b/src/extensions/experimental/language-matcher.cc
@@ -0,0 +1,251 @@
+// 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.
+
+// TODO(cira): Remove LanguageMatcher from v8 when ICU implements
+// language matching API.
+
+#include "language-matcher.h"
+
+#include "i18n-utils.h"
+#include "unicode/datefmt.h" // For getAvailableLocales
+#include "unicode/locid.h"
+#include "unicode/uloc.h"
+#include "utils.h"
+
+namespace v8 {
+namespace internal {
+
+const unsigned int LanguageMatcher::kLanguageWeight = 75;
+const unsigned int LanguageMatcher::kScriptWeight = 20;
+const unsigned int LanguageMatcher::kRegionWeight = 5;
+const unsigned int LanguageMatcher::kThreshold = 50;
+const unsigned int LanguageMatcher::kPositionBonus = 1;
+const char* const LanguageMatcher::kDefaultLocale = "root";
+
+static const char* GetLanguageException(const char*);
+static bool BCP47ToICUFormat(const char*, char*);
+static int CompareLocaleSubtags(const char*, const char*);
+static bool BuildLocaleName(const char*, const char*, LocaleIDMatch*);
+
+LocaleIDMatch::LocaleIDMatch()
+ : score(-1) {
+ I18NUtils::StrNCopy(
+ bcp47_id, ULOC_FULLNAME_CAPACITY, LanguageMatcher::kDefaultLocale);
+
+ I18NUtils::StrNCopy(
+ icu_id, ULOC_FULLNAME_CAPACITY, LanguageMatcher::kDefaultLocale);
+}
+
+LocaleIDMatch& LocaleIDMatch::operator=(const LocaleIDMatch& rhs) {
+ I18NUtils::StrNCopy(this->bcp47_id, ULOC_FULLNAME_CAPACITY, rhs.bcp47_id);
+ I18NUtils::StrNCopy(this->icu_id, ULOC_FULLNAME_CAPACITY, rhs.icu_id);
+ this->score = rhs.score;
+
+ return *this;
+}
+
+// static
+void LanguageMatcher::GetBestMatchForPriorityList(
+ v8::Handle<v8::Array> locales, LocaleIDMatch* result) {
+ v8::HandleScope handle_scope;
+
+ unsigned int position_bonus = locales->Length() * kPositionBonus;
+
+ int max_score = 0;
+ LocaleIDMatch match;
+ for (unsigned int i = 0; i < locales->Length(); ++i) {
+ position_bonus -= kPositionBonus;
+
+ v8::TryCatch try_catch;
+ v8::Local<v8::Value> locale_id = locales->Get(v8::Integer::New(i));
+
+ // Return default if exception is raised when reading parameter.
+ if (try_catch.HasCaught()) break;
+
+ // JavaScript arrays can be heterogenous so check each item
+ // if it's a string.
+ if (!locale_id->IsString()) continue;
+
+ if (!CompareToSupportedLocaleIDList(locale_id->ToString(), &match)) {
+ continue;
+ }
+
+ // Skip items under threshold.
+ if (match.score < kThreshold) continue;
+
+ match.score += position_bonus;
+ if (match.score > max_score) {
+ *result = match;
+
+ max_score = match.score;
+ }
+ }
+}
+
+// static
+void LanguageMatcher::GetBestMatchForString(
+ v8::Handle<v8::String> locale, LocaleIDMatch* result) {
+ LocaleIDMatch match;
+
+ if (CompareToSupportedLocaleIDList(locale, &match) &&
+ match.score >= kThreshold) {
+ *result = match;
+ }
+}
+
+// static
+bool LanguageMatcher::CompareToSupportedLocaleIDList(
+ v8::Handle<v8::String> locale_id, LocaleIDMatch* result) {
+ static int32_t available_count = 0;
+ // Depending on how ICU data is built, locales returned by
+ // Locale::getAvailableLocale() are not guaranteed to support DateFormat,
+ // Collation and other services. We can call getAvailableLocale() of all the
+ // services we want to support and take the intersection of them all, but
+ // using DateFormat::getAvailableLocales() should suffice.
+ // TODO(cira): Maybe make this thread-safe?
+ static const icu::Locale* available_locales =
+ icu::DateFormat::getAvailableLocales(available_count);
+
+ // Skip this locale_id if it's not in ASCII.
+ static LocaleIDMatch default_match;
+ v8::String::AsciiValue ascii_value(locale_id);
+ if (*ascii_value == NULL) return false;
+
+ char locale[ULOC_FULLNAME_CAPACITY];
+ if (!BCP47ToICUFormat(*ascii_value, locale)) return false;
+
+ icu::Locale input_locale(locale);
+
+ // Position of the best match locale in list of available locales.
+ int position = -1;
+ const char* language = GetLanguageException(input_locale.getLanguage());
+ const char* script = input_locale.getScript();
+ const char* region = input_locale.getCountry();
+ for (int32_t i = 0; i < available_count; ++i) {
+ int current_score = 0;
+ int sign =
+ CompareLocaleSubtags(language, available_locales[i].getLanguage());
+ current_score += sign * kLanguageWeight;
+
+ sign = CompareLocaleSubtags(script, available_locales[i].getScript());
+ current_score += sign * kScriptWeight;
+
+ sign = CompareLocaleSubtags(region, available_locales[i].getCountry());
+ current_score += sign * kRegionWeight;
+
+ if (current_score >= kThreshold && current_score > result->score) {
+ result->score = current_score;
+ position = i;
+ }
+ }
+
+ // Didn't find any good matches so use defaults.
+ if (position == -1) return false;
+
+ return BuildLocaleName(available_locales[position].getBaseName(),
+ input_locale.getName(), result);
+}
+
+// For some unsupported language subtags it is better to fallback to related
+// language that is supported than to default.
+static const char* GetLanguageException(const char* language) {
+ // Serbo-croatian to Serbian.
+ if (!strcmp(language, "sh")) return "sr";
+
+ // Norweigan to Norweiaan to Norwegian Bokmal.
+ if (!strcmp(language, "no")) return "nb";
+
+ // Moldavian to Romanian.
+ if (!strcmp(language, "mo")) return "ro";
+
+ // Tagalog to Filipino.
+ if (!strcmp(language, "tl")) return "fil";
+
+ return language;
+}
+
+// Converts user input from BCP47 locale id format to ICU compatible format.
+// Returns false if uloc_forLanguageTag call fails or if extension is too long.
+static bool BCP47ToICUFormat(const char* locale_id, char* result) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t locale_size = 0;
+
+ char locale[ULOC_FULLNAME_CAPACITY];
+ I18NUtils::StrNCopy(locale, ULOC_FULLNAME_CAPACITY, locale_id);
+
+ // uloc_forLanguageTag has a bug where long extension can crash the code.
+ // We need to check if extension part of language id conforms to the length.
+ // ICU bug: http://bugs.icu-project.org/trac/ticket/8519
+ const char* extension = strstr(locale_id, "-u-");
+ if (extension != NULL &&
+ strlen(extension) > ULOC_KEYWORD_AND_VALUES_CAPACITY) {
+ // Truncate to get non-crashing string, but still preserve base language.
+ int base_length = strlen(locale_id) - strlen(extension);
+ locale[base_length] = '\0';
+ }
+
+ uloc_forLanguageTag(locale, result, ULOC_FULLNAME_CAPACITY,
+ &locale_size, &status);
+ return !U_FAILURE(status);
+}
+
+// Compares locale id subtags.
+// Returns 1 for match or -1 for mismatch.
+static int CompareLocaleSubtags(const char* lsubtag, const char* rsubtag) {
+ return strcmp(lsubtag, rsubtag) == 0 ? 1 : -1;
+}
+
+// Builds a BCP47 compliant locale id from base name of matched locale and
+// full user specified locale.
+// Returns false if uloc_toLanguageTag failed to convert locale id.
+// Example:
+// base_name of matched locale (ICU ID): de_DE
+// input_locale_name (ICU ID): de_AT@collation=phonebk
+// result (ICU ID): de_DE@collation=phonebk
+// result (BCP47 ID): de-DE-u-co-phonebk
+static bool BuildLocaleName(const char* base_name,
+ const char* input_locale_name,
+ LocaleIDMatch* result) {
+ I18NUtils::StrNCopy(result->icu_id, ULOC_LANG_CAPACITY, base_name);
+
+ // Get extensions (if any) from the original locale.
+ const char* extension = strchr(input_locale_name, ULOC_KEYWORD_SEPARATOR);
+ if (extension != NULL) {
+ I18NUtils::StrNCopy(result->icu_id + strlen(base_name),
+ ULOC_KEYWORD_AND_VALUES_CAPACITY, extension);
+ } else {
+ I18NUtils::StrNCopy(result->icu_id, ULOC_LANG_CAPACITY, base_name);
+ }
+
+ // Convert ICU locale name into BCP47 format.
+ UErrorCode status = U_ZERO_ERROR;
+ uloc_toLanguageTag(result->icu_id, result->bcp47_id,
+ ULOC_FULLNAME_CAPACITY, false, &status);
+ return !U_FAILURE(status);
+}
+
+} } // namespace v8::internal
diff --git a/src/extensions/experimental/language-matcher.h b/src/extensions/experimental/language-matcher.h
new file mode 100644
index 0000000..b5336a2
--- /dev/null
+++ b/src/extensions/experimental/language-matcher.h
@@ -0,0 +1,95 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_EXTENSIONS_EXPERIMENTAL_LANGUAGE_MATCHER_H_
+#define V8_EXTENSIONS_EXPERIMENTAL_LANGUAGE_MATCHER_H_
+
+#include <v8.h>
+
+#include "unicode/uloc.h"
+
+namespace v8 {
+namespace internal {
+
+struct LocaleIDMatch {
+ LocaleIDMatch();
+
+ LocaleIDMatch& operator=(const LocaleIDMatch& rhs);
+
+ // Bcp47 locale id - "de-Latn-DE-u-co-phonebk".
+ char bcp47_id[ULOC_FULLNAME_CAPACITY];
+
+ // ICU locale id - "de_Latn_DE@collation=phonebk".
+ char icu_id[ULOC_FULLNAME_CAPACITY];
+
+ // Score for this locale.
+ int score;
+};
+
+class LanguageMatcher {
+ public:
+ // Default locale.
+ static const char* const kDefaultLocale;
+
+ // Finds best supported locale for a given a list of locale identifiers.
+ // It preserves the extension for the locale id.
+ static void GetBestMatchForPriorityList(
+ v8::Handle<v8::Array> locale_list, LocaleIDMatch* result);
+
+ // Finds best supported locale for a single locale identifier.
+ // It preserves the extension for the locale id.
+ static void GetBestMatchForString(
+ v8::Handle<v8::String> locale_id, LocaleIDMatch* result);
+
+ private:
+ // If langauge subtags match add this amount to the score.
+ static const unsigned int kLanguageWeight;
+
+ // If script subtags match add this amount to the score.
+ static const unsigned int kScriptWeight;
+
+ // If region subtags match add this amount to the score.
+ static const unsigned int kRegionWeight;
+
+ // LocaleID match score has to be over this number to accept the match.
+ static const unsigned int kThreshold;
+
+ // For breaking ties in priority queue.
+ static const unsigned int kPositionBonus;
+
+ LanguageMatcher();
+
+ // Compares locale_id to the supported list of locales and returns best
+ // match.
+ // Returns false if it fails to convert locale id from ICU to BCP47 format.
+ static bool CompareToSupportedLocaleIDList(v8::Handle<v8::String> locale_id,
+ LocaleIDMatch* result);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_EXTENSIONS_EXPERIMENTAL_LANGUAGE_MATCHER_H_
diff --git a/src/preparse-data-format.h b/src/preparse-data-format.h
new file mode 100644
index 0000000..64c4f18
--- /dev/null
+++ b/src/preparse-data-format.h
@@ -0,0 +1,62 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PREPARSE_DATA_FORMAT_H_
+#define V8_PREPARSE_DATA_FORMAT_H_
+
+namespace v8 {
+namespace internal {
+
+// Generic and general data used by preparse data recorders and readers.
+
+struct PreparseDataConstants {
+ public:
+ // Layout and constants of the preparse data exchange format.
+ static const unsigned kMagicNumber = 0xBadDead;
+ static const unsigned kCurrentVersion = 6;
+
+ static const int kMagicOffset = 0;
+ static const int kVersionOffset = 1;
+ static const int kHasErrorOffset = 2;
+ static const int kFunctionsSizeOffset = 3;
+ static const int kSymbolCountOffset = 4;
+ static const int kSizeOffset = 5;
+ static const int kHeaderSize = 6;
+
+ // If encoding a message, the following positions are fixed.
+ static const int kMessageStartPos = 0;
+ static const int kMessageEndPos = 1;
+ static const int kMessageArgCountPos = 2;
+ static const int kMessageTextPos = 3;
+
+ static const unsigned char kNumberTerminator = 0x80u;
+};
+
+
+} } // namespace v8::internal.
+
+#endif // V8_PREPARSE_DATA_FORMAT_H_
diff --git a/src/version.cc b/src/version.cc
index 5cc81ac..dd89f61 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -35,7 +35,7 @@
#define MAJOR_VERSION 3
#define MINOR_VERSION 3
#define BUILD_NUMBER 5
-#define PATCH_LEVEL 0
+#define PATCH_LEVEL 1
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
new file mode 100644
index 0000000..ba0fdb2
--- /dev/null
+++ b/test/cctest/test-lockers.cc
@@ -0,0 +1,605 @@
+// Copyright 2007-2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <limits.h>
+
+#include "v8.h"
+
+#include "api.h"
+#include "isolate.h"
+#include "compilation-cache.h"
+#include "execution.h"
+#include "snapshot.h"
+#include "platform.h"
+#include "utils.h"
+#include "cctest.h"
+#include "parser.h"
+#include "unicode-inl.h"
+
+using ::v8::AccessorInfo;
+using ::v8::Context;
+using ::v8::Extension;
+using ::v8::Function;
+using ::v8::HandleScope;
+using ::v8::Local;
+using ::v8::Object;
+using ::v8::ObjectTemplate;
+using ::v8::Persistent;
+using ::v8::Script;
+using ::v8::String;
+using ::v8::Value;
+using ::v8::V8;
+
+namespace i = ::i;
+
+
+
+
+// Migrating an isolate
+class KangarooThread : public v8::internal::Thread {
+ public:
+ KangarooThread(v8::Isolate* isolate,
+ v8::Handle<v8::Context> context, int value)
+ : Thread(NULL, "KangarooThread"),
+ isolate_(isolate), context_(context), value_(value) {
+ }
+
+ void Run() {
+ {
+ v8::Locker locker(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ CHECK_EQ(isolate_, v8::internal::Isolate::Current());
+ v8::HandleScope scope;
+ v8::Context::Scope context_scope(context_);
+ Local<Value> v = CompileRun("getValue()");
+ CHECK(v->IsNumber());
+ CHECK_EQ(30, static_cast<int>(v->NumberValue()));
+ }
+ {
+ v8::Locker locker(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ v8::Context::Scope context_scope(context_);
+ v8::HandleScope scope;
+ Local<Value> v = CompileRun("getValue()");
+ CHECK(v->IsNumber());
+ CHECK_EQ(30, static_cast<int>(v->NumberValue()));
+ }
+ isolate_->Dispose();
+ }
+
+ private:
+ v8::Isolate* isolate_;
+ Persistent<v8::Context> context_;
+ int value_;
+};
+
+// Migrates an isolate from one thread to another
+TEST(KangarooIsolates) {
+ v8::Isolate* isolate = v8::Isolate::New();
+ Persistent<v8::Context> context;
+ {
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope;
+ context = v8::Context::New();
+ v8::Context::Scope context_scope(context);
+ CHECK_EQ(isolate, v8::internal::Isolate::Current());
+ CompileRun("function getValue() { return 30; }");
+ }
+ KangarooThread thread1(isolate, context, 1);
+ thread1.Start();
+ thread1.Join();
+}
+
+static void CalcFibAndCheck() {
+ Local<Value> v = CompileRun("function fib(n) {"
+ " if (n <= 2) return 1;"
+ " return fib(n-1) + fib(n-2);"
+ "}"
+ "fib(10)");
+ CHECK(v->IsNumber());
+ CHECK_EQ(55, static_cast<int>(v->NumberValue()));
+}
+
+class JoinableThread {
+ public:
+ explicit JoinableThread(const char* name)
+ : name_(name),
+ semaphore_(i::OS::CreateSemaphore(0)),
+ thread_(this) {
+ }
+
+ virtual ~JoinableThread() {
+ delete semaphore_;
+ }
+
+ void Start() {
+ thread_.Start();
+ }
+
+ void Join() {
+ semaphore_->Wait();
+ }
+
+ virtual void Run() = 0;
+ private:
+ class ThreadWithSemaphore : public i::Thread {
+ public:
+ explicit ThreadWithSemaphore(JoinableThread* joinable_thread)
+ : Thread(NULL, joinable_thread->name_),
+ joinable_thread_(joinable_thread) {
+ }
+
+ virtual void Run() {
+ joinable_thread_->Run();
+ joinable_thread_->semaphore_->Signal();
+ }
+
+ private:
+ JoinableThread* joinable_thread_;
+ };
+
+ const char* name_;
+ i::Semaphore* semaphore_;
+ ThreadWithSemaphore thread_;
+
+ friend class ThreadWithSemaphore;
+
+ DISALLOW_COPY_AND_ASSIGN(JoinableThread);
+};
+
+
+class IsolateLockingThreadWithLocalContext : public JoinableThread {
+ public:
+ explicit IsolateLockingThreadWithLocalContext(v8::Isolate* isolate)
+ : JoinableThread("IsolateLockingThread"),
+ isolate_(isolate) {
+ }
+
+ virtual void Run() {
+ v8::Locker locker(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ v8::HandleScope handle_scope;
+ LocalContext local_context;
+ CHECK_EQ(isolate_, v8::internal::Isolate::Current());
+ CalcFibAndCheck();
+ }
+ private:
+ v8::Isolate* isolate_;
+};
+
+static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) {
+ for (int i = 0; i < threads.length(); i++) {
+ threads[i]->Start();
+ }
+ for (int i = 0; i < threads.length(); i++) {
+ threads[i]->Join();
+ }
+ for (int i = 0; i < threads.length(); i++) {
+ delete threads[i];
+ }
+}
+
+
+// Run many threads all locking on the same isolate
+TEST(IsolateLockingStress) {
+ const int kNThreads = 100;
+ i::List<JoinableThread*> threads(kNThreads);
+ v8::Isolate* isolate = v8::Isolate::New();
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new IsolateLockingThreadWithLocalContext(isolate));
+ }
+ StartJoinAndDeleteThreads(threads);
+ isolate->Dispose();
+}
+
+class IsolateNonlockingThread : public JoinableThread {
+ public:
+ explicit IsolateNonlockingThread()
+ : JoinableThread("IsolateNonlockingThread") {
+ }
+
+ virtual void Run() {
+ v8::Isolate* isolate = v8::Isolate::New();
+ {
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = v8::Context::New();
+ v8::Context::Scope context_scope(context);
+ CHECK_EQ(isolate, v8::internal::Isolate::Current());
+ CalcFibAndCheck();
+ }
+ isolate->Dispose();
+ }
+ private:
+};
+
+// Run many threads each accessing its own isolate without locking
+TEST(MultithreadedParallelIsolates) {
+ const int kNThreads = 50;
+ i::List<JoinableThread*> threads(kNThreads);
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new IsolateNonlockingThread());
+ }
+ StartJoinAndDeleteThreads(threads);
+}
+
+
+class IsolateNestedLockingThread : public JoinableThread {
+ public:
+ explicit IsolateNestedLockingThread(v8::Isolate* isolate)
+ : JoinableThread("IsolateNestedLocking"), isolate_(isolate) {
+ }
+ virtual void Run() {
+ v8::Locker lock(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ v8::HandleScope handle_scope;
+ LocalContext local_context;
+ {
+ v8::Locker another_lock(isolate_);
+ CalcFibAndCheck();
+ }
+ {
+ v8::Locker another_lock(isolate_);
+ CalcFibAndCheck();
+ }
+ }
+ private:
+ v8::Isolate* isolate_;
+};
+
+// Run many threads with nested locks
+TEST(IsolateNestedLocking) {
+ const int kNThreads = 100;
+ v8::Isolate* isolate = v8::Isolate::New();
+ i::List<JoinableThread*> threads(kNThreads);
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new IsolateNestedLockingThread(isolate));
+ }
+ StartJoinAndDeleteThreads(threads);
+}
+
+
+class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread {
+ public:
+ SeparateIsolatesLocksNonexclusiveThread(v8::Isolate* isolate1,
+ v8::Isolate* isolate2)
+ : JoinableThread("SeparateIsolatesLocksNonexclusiveThread"),
+ isolate1_(isolate1), isolate2_(isolate2) {
+ }
+
+ virtual void Run() {
+ v8::Locker lock(isolate1_);
+ v8::Isolate::Scope isolate_scope(isolate1_);
+ v8::HandleScope handle_scope;
+ LocalContext local_context;
+
+ IsolateLockingThreadWithLocalContext threadB(isolate2_);
+ threadB.Start();
+ CalcFibAndCheck();
+ threadB.Join();
+ }
+ private:
+ v8::Isolate* isolate1_;
+ v8::Isolate* isolate2_;
+};
+
+// Run parallel threads that lock and access different isolates in parallel
+TEST(SeparateIsolatesLocksNonexclusive) {
+ const int kNThreads = 100;
+ v8::Isolate* isolate1 = v8::Isolate::New();
+ v8::Isolate* isolate2 = v8::Isolate::New();
+ i::List<JoinableThread*> threads(kNThreads);
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new SeparateIsolatesLocksNonexclusiveThread(isolate1,
+ isolate2));
+ }
+ StartJoinAndDeleteThreads(threads);
+ isolate2->Dispose();
+ isolate1->Dispose();
+}
+
+class LockIsolateAndCalculateFibSharedContextThread : public JoinableThread {
+ public:
+ explicit LockIsolateAndCalculateFibSharedContextThread(
+ v8::Isolate* isolate, v8::Handle<v8::Context> context)
+ : JoinableThread("LockIsolateAndCalculateFibThread"),
+ isolate_(isolate),
+ context_(context) {
+ }
+
+ virtual void Run() {
+ v8::Locker lock(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ HandleScope handle_scope;
+ v8::Context::Scope context_scope(context_);
+ CalcFibAndCheck();
+ }
+ private:
+ v8::Isolate* isolate_;
+ Persistent<v8::Context> context_;
+};
+
+class LockerUnlockerThread : public JoinableThread {
+ public:
+ explicit LockerUnlockerThread(v8::Isolate* isolate)
+ : JoinableThread("LockerUnlockerThread"),
+ isolate_(isolate) {
+ }
+
+ virtual void Run() {
+ v8::Locker lock(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = v8::Context::New();
+ {
+ v8::Context::Scope context_scope(context);
+ CalcFibAndCheck();
+ }
+ {
+ isolate_->Exit();
+ v8::Unlocker unlocker(isolate_);
+ LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
+ thread.Start();
+ thread.Join();
+ }
+ isolate_->Enter();
+ {
+ v8::Context::Scope context_scope(context);
+ CalcFibAndCheck();
+ }
+ }
+ private:
+ v8::Isolate* isolate_;
+};
+
+// Use unlocker inside of a Locker, multiple threads.
+TEST(LockerUnlocker) {
+ const int kNThreads = 100;
+ i::List<JoinableThread*> threads(kNThreads);
+ v8::Isolate* isolate = v8::Isolate::New();
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new LockerUnlockerThread(isolate));
+ }
+ StartJoinAndDeleteThreads(threads);
+ isolate->Dispose();
+}
+
+class LockTwiceAndUnlockThread : public JoinableThread {
+ public:
+ explicit LockTwiceAndUnlockThread(v8::Isolate* isolate)
+ : JoinableThread("LockTwiceAndUnlockThread"),
+ isolate_(isolate) {
+ }
+
+ virtual void Run() {
+ v8::Locker lock(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = v8::Context::New();
+ {
+ v8::Context::Scope context_scope(context);
+ CalcFibAndCheck();
+ }
+ {
+ v8::Locker second_lock(isolate_);
+ {
+ isolate_->Exit();
+ v8::Unlocker unlocker(isolate_);
+ LockIsolateAndCalculateFibSharedContextThread thread(isolate_, context);
+ thread.Start();
+ thread.Join();
+ }
+ }
+ isolate_->Enter();
+ {
+ v8::Context::Scope context_scope(context);
+ CalcFibAndCheck();
+ }
+ }
+ private:
+ v8::Isolate* isolate_;
+};
+
+// Use Unlocker inside two Lockers.
+TEST(LockTwiceAndUnlock) {
+ const int kNThreads = 100;
+ i::List<JoinableThread*> threads(kNThreads);
+ v8::Isolate* isolate = v8::Isolate::New();
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new LockTwiceAndUnlockThread(isolate));
+ }
+ StartJoinAndDeleteThreads(threads);
+ isolate->Dispose();
+}
+
+class LockAndUnlockDifferentIsolatesThread : public JoinableThread {
+ public:
+ LockAndUnlockDifferentIsolatesThread(v8::Isolate* isolate1,
+ v8::Isolate* isolate2)
+ : JoinableThread("LockAndUnlockDifferentIsolatesThread"),
+ isolate1_(isolate1),
+ isolate2_(isolate2) {
+ }
+
+ virtual void Run() {
+ Persistent<v8::Context> context1;
+ Persistent<v8::Context> context2;
+ v8::Locker lock1(isolate1_);
+ CHECK(v8::Locker::IsLocked(isolate1_));
+ CHECK(!v8::Locker::IsLocked(isolate2_));
+ {
+ v8::Isolate::Scope isolate_scope(isolate1_);
+ v8::HandleScope handle_scope;
+ context1 = v8::Context::New();
+ {
+ v8::Context::Scope context_scope(context1);
+ CalcFibAndCheck();
+ }
+ }
+ v8::Locker lock2(isolate2_);
+ CHECK(v8::Locker::IsLocked(isolate1_));
+ CHECK(v8::Locker::IsLocked(isolate2_));
+ {
+ v8::Isolate::Scope isolate_scope(isolate2_);
+ v8::HandleScope handle_scope;
+ context2 = v8::Context::New();
+ {
+ v8::Context::Scope context_scope(context2);
+ CalcFibAndCheck();
+ }
+ }
+ {
+ v8::Unlocker unlock1(isolate1_);
+ CHECK(!v8::Locker::IsLocked(isolate1_));
+ CHECK(v8::Locker::IsLocked(isolate2_));
+ v8::Isolate::Scope isolate_scope(isolate2_);
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(context2);
+ LockIsolateAndCalculateFibSharedContextThread thread(isolate1_, context1);
+ thread.Start();
+ CalcFibAndCheck();
+ thread.Join();
+ }
+ }
+ private:
+ v8::Isolate* isolate1_;
+ v8::Isolate* isolate2_;
+};
+
+// Lock two isolates and unlock one of them.
+TEST(LockAndUnlockDifferentIsolates) {
+ v8::Isolate* isolate1 = v8::Isolate::New();
+ v8::Isolate* isolate2 = v8::Isolate::New();
+ LockAndUnlockDifferentIsolatesThread thread(isolate1, isolate2);
+ thread.Start();
+ thread.Join();
+ isolate2->Dispose();
+ isolate1->Dispose();
+}
+
+class LockUnlockLockThread : public JoinableThread {
+ public:
+ LockUnlockLockThread(v8::Isolate* isolate, v8::Handle<v8::Context> context)
+ : JoinableThread("LockUnlockLockThread"),
+ isolate_(isolate),
+ context_(context) {
+ }
+
+ virtual void Run() {
+ v8::Locker lock1(isolate_);
+ CHECK(v8::Locker::IsLocked(isolate_));
+ CHECK(!v8::Locker::IsLocked());
+ {
+ v8::Isolate::Scope isolate_scope(isolate_);
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(context_);
+ CalcFibAndCheck();
+ }
+ {
+ v8::Unlocker unlock1(isolate_);
+ CHECK(!v8::Locker::IsLocked(isolate_));
+ CHECK(!v8::Locker::IsLocked());
+ {
+ v8::Locker lock2(isolate_);
+ v8::Isolate::Scope isolate_scope(isolate_);
+ v8::HandleScope handle_scope;
+ CHECK(v8::Locker::IsLocked(isolate_));
+ CHECK(!v8::Locker::IsLocked());
+ v8::Context::Scope context_scope(context_);
+ CalcFibAndCheck();
+ }
+ }
+ }
+
+ private:
+ v8::Isolate* isolate_;
+ v8::Persistent<v8::Context> context_;
+};
+
+// Locker inside an Unlocker inside a Locker.
+TEST(LockUnlockLockMultithreaded) {
+ const int kNThreads = 100;
+ v8::Isolate* isolate = v8::Isolate::New();
+ Persistent<v8::Context> context;
+ {
+ v8::Locker locker_(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope;
+ context = v8::Context::New();
+ }
+ i::List<JoinableThread*> threads(kNThreads);
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new LockUnlockLockThread(isolate, context));
+ }
+ StartJoinAndDeleteThreads(threads);
+}
+
+class LockUnlockLockDefaultIsolateThread : public JoinableThread {
+ public:
+ explicit LockUnlockLockDefaultIsolateThread(v8::Handle<v8::Context> context)
+ : JoinableThread("LockUnlockLockDefaultIsolateThread"),
+ context_(context) {
+ }
+
+ virtual void Run() {
+ v8::Locker lock1;
+ {
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(context_);
+ CalcFibAndCheck();
+ }
+ {
+ v8::Unlocker unlock1;
+ {
+ v8::Locker lock2;
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(context_);
+ CalcFibAndCheck();
+ }
+ }
+ }
+
+ private:
+ v8::Persistent<v8::Context> context_;
+};
+
+// Locker inside an Unlocker inside a Locker for default isolate.
+TEST(LockUnlockLockDefaultIsolateMultithreaded) {
+ const int kNThreads = 100;
+ Persistent<v8::Context> context;
+ {
+ v8::Locker locker_;
+ v8::HandleScope handle_scope;
+ context = v8::Context::New();
+ }
+ i::List<JoinableThread*> threads(kNThreads);
+ for (int i = 0; i < kNThreads; i++) {
+ threads.Add(new LockUnlockLockDefaultIsolateThread(context));
+ }
+ StartJoinAndDeleteThreads(threads);
+}
diff --git a/test/mjsunit/assert-opt-and-deopt.js b/test/mjsunit/assert-opt-and-deopt.js
new file mode 100644
index 0000000..b624ba5
--- /dev/null
+++ b/test/mjsunit/assert-opt-and-deopt.js
@@ -0,0 +1,181 @@
+// 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.
+
+// Flags: --allow-natives-syntax
+
+/**
+ * This class shows how to use %GetOptimizationCount() and
+ * %GetOptimizationStatus() to infer information about opts and deopts.
+ * Might be nice to put this into mjsunit.js, but that doesn't depend on
+ * the --allow-natives-syntax flag so far.
+ */
+function OptTracker() {
+ this.opt_counts_ = {};
+}
+
+/**
+ * The possible optimization states of a function. Must be in sync with the
+ * return values of Runtime_GetOptimizationStatus() in runtime.cc!
+ * @enum {int}
+ */
+OptTracker.OptimizationState = {
+ YES: 1,
+ NO: 2,
+ ALWAYS: 3,
+ NEVER: 4
+};
+
+/**
+ * Always call this at the beginning of your test, once for each function
+ * that you later want to track de/optimizations for. It is necessary because
+ * tests are sometimes executed several times in a row, and you want to
+ * disregard counts from previous runs.
+ */
+OptTracker.prototype.CheckpointOptCount = function(func) {
+ this.opt_counts_[func] = %GetOptimizationCount(func);
+};
+
+OptTracker.prototype.AssertOptCount = function(func, optcount) {
+ if (this.DisableAsserts_(func)) {
+ return;
+ }
+ assertEquals(optcount, this.GetOptCount_(func));
+};
+
+OptTracker.prototype.AssertDeoptCount = function(func, deopt_count) {
+ if (this.DisableAsserts_(func)) {
+ return;
+ }
+ assertEquals(deopt_count, this.GetDeoptCount_(func));
+};
+
+OptTracker.prototype.AssertDeoptHappened = function(func, expect_deopt) {
+ if (this.DisableAsserts_(func)) {
+ return;
+ }
+ if (expect_deopt) {
+ assertTrue(this.GetDeoptCount_(func) > 0);
+ } else {
+ assertEquals(0, this.GetDeoptCount_(func));
+ }
+}
+
+OptTracker.prototype.AssertIsOptimized = function(func, expect_optimized) {
+ if (this.DisableAsserts_(func)) {
+ return;
+ }
+ var raw_optimized = %GetOptimizationStatus(func);
+ if (expect_optimized) {
+ assertEquals(OptTracker.OptimizationState.YES, raw_optimized);
+ } else {
+ assertEquals(OptTracker.OptimizationState.NO, raw_optimized);
+ }
+}
+
+/**
+ * @private
+ */
+OptTracker.prototype.GetOptCount_ = function(func) {
+ var raw_count = %GetOptimizationCount(func);
+ if (func in this.opt_counts_) {
+ var checkpointed_count = this.opt_counts_[func];
+ return raw_count - checkpointed_count;
+ }
+ return raw_count;
+}
+
+/**
+ * @private
+ */
+OptTracker.prototype.GetDeoptCount_ = function(func) {
+ var count = this.GetOptCount_(func);
+ if (%GetOptimizationStatus(func) == OptTracker.OptimizationState.YES) {
+ count -= 1;
+ }
+ return count;
+}
+
+/**
+ * @private
+ */
+OptTracker.prototype.DisableAsserts_ = function(func) {
+ switch(%GetOptimizationStatus(func)) {
+ case OptTracker.OptimizationState.YES:
+ case OptTracker.OptimizationState.NO:
+ return false;
+ case OptTracker.OptimizationState.ALWAYS:
+ case OptTracker.OptimizationState.NEVER:
+ return true;
+ }
+ return false;
+}
+// (End of class OptTracker.)
+
+// Example function used by the test below.
+function f(a) {
+ return a+1;
+}
+
+var tracker = new OptTracker();
+tracker.CheckpointOptCount(f);
+
+tracker.AssertOptCount(f, 0);
+tracker.AssertIsOptimized(f, false);
+tracker.AssertDeoptHappened(f, false);
+tracker.AssertDeoptCount(f, 0);
+
+for (var i = 0; i < 5; i++) f(1);
+
+tracker.AssertOptCount(f, 0);
+tracker.AssertIsOptimized(f, false);
+tracker.AssertDeoptHappened(f, false);
+tracker.AssertDeoptCount(f, 0);
+
+%OptimizeFunctionOnNextCall(f);
+f(1);
+
+tracker.AssertOptCount(f, 1);
+tracker.AssertIsOptimized(f, true);
+tracker.AssertDeoptHappened(f, false);
+tracker.AssertDeoptCount(f, 0);
+
+%DeoptimizeFunction(f);
+
+tracker.AssertOptCount(f, 1);
+tracker.AssertIsOptimized(f, false);
+tracker.AssertDeoptHappened(f, true);
+tracker.AssertDeoptCount(f, 1);
+
+// Let's trigger optimization for another type.
+for (var i = 0; i < 5; i++) f("a");
+%OptimizeFunctionOnNextCall(f);
+f("b");
+
+tracker.AssertOptCount(f, 2);
+tracker.AssertIsOptimized(f, true);
+tracker.AssertDeoptHappened(f, true);
+tracker.AssertDeoptCount(f, 1);
diff --git a/test/mjsunit/function-call.js b/test/mjsunit/function-call.js
new file mode 100644
index 0000000..58d61af
--- /dev/null
+++ b/test/mjsunit/function-call.js
@@ -0,0 +1,326 @@
+// 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.
+
+
+var should_throw_on_null_and_undefined =
+ [Object.prototype.toLocaleString,
+ Object.prototype.valueOf,
+ Object.prototype.hasOwnProperty,
+ Object.prototype.isPrototypeOf,
+ Object.prototype.propertyIsEnumerable,
+ Array.prototype.concat,
+ Array.prototype.join,
+ Array.prototype.pop,
+ Array.prototype.push,
+ Array.prototype.reverse,
+ Array.prototype.shift,
+ Array.prototype.slice,
+ Array.prototype.sort,
+ Array.prototype.splice,
+ Array.prototype.unshift,
+ Array.prototype.indexOf,
+ Array.prototype.lastIndexOf,
+ Array.prototype.every,
+ Array.prototype.some,
+ Array.prototype.forEach,
+ Array.prototype.map,
+ Array.prototype.filter,
+ Array.prototype.reduce,
+ Array.prototype.reduceRight,
+ String.prototype.charAt,
+ String.prototype.charCodeAt,
+ String.prototype.concat,
+ String.prototype.indexOf,
+ String.prototype.lastIndexOf,
+ String.prototype.localeCompare,
+ String.prototype.match,
+ String.prototype.replace,
+ String.prototype.search,
+ String.prototype.slice,
+ String.prototype.split,
+ String.prototype.substring,
+ String.prototype.toLowerCase,
+ String.prototype.toLocaleLowerCase,
+ String.prototype.toUpperCase,
+ String.prototype.toLocaleUpperCase,
+ String.prototype.trim,
+ Number.prototype.toLocaleString,
+ Error.prototype.toString];
+
+// Non generic natives do not work on any input other than the specific
+// type, but since this change will allow call to be invoked with undefined
+// or null as this we still explicitly test that we throw on these here.
+var non_generic =
+ [Array.prototype.toString,
+ Array.prototype.toLocaleString,
+ Function.prototype.toString,
+ Function.prototype.call,
+ Function.prototype.apply,
+ String.prototype.toString,
+ String.prototype.valueOf,
+ Boolean.prototype.toString,
+ Boolean.prototype.valueOf,
+ Number.prototype.toString,
+ Number.prototype.valueOf,
+ Number.prototype.toFixed,
+ Number.prototype.toExponential,
+ Number.prototype.toPrecision,
+ Date.prototype.toString,
+ Date.prototype.toDateString,
+ Date.prototype.toTimeString,
+ Date.prototype.toLocaleString,
+ Date.prototype.toLocaleDateString,
+ Date.prototype.toLocaleTimeString,
+ Date.prototype.valueOf,
+ Date.prototype.getTime,
+ Date.prototype.getFullYear,
+ Date.prototype.getUTCFullYear,
+ Date.prototype.getMonth,
+ Date.prototype.getUTCMonth,
+ Date.prototype.getDate,
+ Date.prototype.getUTCDate,
+ Date.prototype.getDay,
+ Date.prototype.getUTCDay,
+ Date.prototype.getHours,
+ Date.prototype.getUTCHours,
+ Date.prototype.getMinutes,
+ Date.prototype.getUTCMinutes,
+ Date.prototype.getSeconds,
+ Date.prototype.getUTCSeconds,
+ Date.prototype.getMilliseconds,
+ Date.prototype.getUTCMilliseconds,
+ Date.prototype.getTimezoneOffset,
+ Date.prototype.setTime,
+ Date.prototype.setMilliseconds,
+ Date.prototype.setUTCMilliseconds,
+ Date.prototype.setSeconds,
+ Date.prototype.setUTCSeconds,
+ Date.prototype.setMinutes,
+ Date.prototype.setUTCMinutes,
+ Date.prototype.setHours,
+ Date.prototype.setUTCHours,
+ Date.prototype.setDate,
+ Date.prototype.setUTCDate,
+ Date.prototype.setMonth,
+ Date.prototype.setUTCMonth,
+ Date.prototype.setFullYear,
+ Date.prototype.setUTCFullYear,
+ Date.prototype.toUTCString,
+ Date.prototype.toISOString,
+ Date.prototype.toJSON,
+ RegExp.prototype.exec,
+ RegExp.prototype.test,
+ RegExp.prototype.toString];
+
+
+// Mapping functions.
+var mapping_functions =
+ [Array.prototype.every,
+ Array.prototype.some,
+ Array.prototype.forEach,
+ Array.prototype.map,
+ Array.prototype.filter];
+
+// Reduce functions.
+var reducing_functions =
+ [Array.prototype.reduce,
+ Array.prototype.reduceRight];
+
+// Test that all natives using the ToObject call throw the right exception.
+for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
+ // Sanity check that all functions are correct
+ assertEquals(typeof(should_throw_on_null_and_undefined[i]), "function");
+
+ try {
+ // We call all functions with no parameters, which means that essential
+ // parameters will have the undefined value.
+ // The test for whether the "this" value is null or undefined is always
+ // performed before access to the other parameters, so even if the
+ // undefined value is an invalid argument value, it mustn't change
+ // the result of the test.
+ should_throw_on_null_and_undefined[i].call(null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+
+ try {
+ should_throw_on_null_and_undefined[i].call(undefined);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+
+ try {
+ should_throw_on_null_and_undefined[i].apply(null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+
+ try {
+ should_throw_on_null_and_undefined[i].apply(undefined);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+}
+
+// Test that all natives that are non generic throw on null and undefined.
+for (var i = 0; i < non_generic.length; i++) {
+ // Sanity check that all functions are correct
+ assertEquals(typeof(non_generic[i]), "function");
+ try {
+ non_generic[i].call(null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+
+ try {
+ non_generic[i].call(null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+
+ try {
+ non_generic[i].apply(null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+
+ try {
+ non_generic[i].apply(null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+}
+
+
+// Test that we still throw when calling with thisArg null or undefined
+// through an array mapping function.
+var array = [1,2,3,4,5];
+for (var j = 0; j < mapping_functions.length; j++) {
+ for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
+ try {
+ mapping_functions[j].call(array,
+ should_throw_on_null_and_undefined[i],
+ null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+
+ try {
+ mapping_functions[j].call(array,
+ should_throw_on_null_and_undefined[i],
+ undefined);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+ }
+}
+
+for (var j = 0; j < mapping_functions.length; j++) {
+ for (var i = 0; i < non_generic.length; i++) {
+ try {
+ mapping_functions[j].call(array,
+ non_generic[i],
+ null);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+
+ try {
+ mapping_functions[j].call(array,
+ non_generic[i],
+ undefined);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+ }
+}
+
+
+// Reduce functions do a call with null as this argument.
+for (var j = 0; j < reducing_functions.length; j++) {
+ for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
+ try {
+ reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+
+ try {
+ reducing_functions[j].call(array, should_throw_on_null_and_undefined[i]);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue("called_on_null_or_undefined" == e.type ||
+ "null_to_object" == e.type);
+ }
+ }
+}
+
+for (var j = 0; j < reducing_functions.length; j++) {
+ for (var i = 0; i < non_generic.length; i++) {
+ try {
+ reducing_functions[j].call(array, non_generic[i]);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+
+ try {
+ reducing_functions[j].call(array, non_generic[i]);
+ assertUnreachable();
+ } catch (e) {
+ assertTrue(e instanceof TypeError);
+ }
+ }
+}
+
+
+// Object.prototype.toString()
+assertEquals(Object.prototype.toString.call(null),
+ '[object Null]')
+
+assertEquals(Object.prototype.toString.call(undefined),
+ '[object Undefined]')
diff --git a/test/mjsunit/regress/regress-1369.js b/test/mjsunit/regress/regress-1369.js
new file mode 100644
index 0000000..f18e37b
--- /dev/null
+++ b/test/mjsunit/regress/regress-1369.js
@@ -0,0 +1,31 @@
+// 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.
+
+// Flags: --expose-gc
+
+assertThrows('gc.call(1)');
+assertThrows('gc.call("asdf")');
diff --git a/test/preparser/non-use-strict-hex-escape.js b/test/preparser/non-use-strict-hex-escape.js
new file mode 100644
index 0000000..bf28923
--- /dev/null
+++ b/test/preparser/non-use-strict-hex-escape.js
@@ -0,0 +1,35 @@
+// 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.
+
+// A string looking like "use strict", but with a hex escape in it,
+// doesn't trigger strict mode.
+
+function foo() {
+ "use\x20strict";
+ var x = "hello\040world";
+ return x;
+}
\ No newline at end of file
diff --git a/test/preparser/non-use-strict-octal-escape.js b/test/preparser/non-use-strict-octal-escape.js
new file mode 100644
index 0000000..9e00742
--- /dev/null
+++ b/test/preparser/non-use-strict-octal-escape.js
@@ -0,0 +1,35 @@
+// 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.
+
+// A string looking like "use strict", but with an octal escape in it,
+// doesn't trigger strict mode.
+
+function foo() {
+ "use\040strict";
+ var x = "hello\040world";
+ return x;
+}
\ No newline at end of file
diff --git a/test/preparser/non-use-strict-uhex-escape.js b/test/preparser/non-use-strict-uhex-escape.js
new file mode 100644
index 0000000..5fba673
--- /dev/null
+++ b/test/preparser/non-use-strict-uhex-escape.js
@@ -0,0 +1,35 @@
+// 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.
+
+// A string looking like "use strict", but with a long hex escape in it,
+// doesn't trigger strict mode.
+
+function foo() {
+ "use\u0020strict";
+ var x = "hello\040world";
+ return x;
+}
\ No newline at end of file
diff --git a/test/preparser/preparser.expectation b/test/preparser/preparser.expectation
new file mode 100644
index 0000000..7f7e0e2
--- /dev/null
+++ b/test/preparser/preparser.expectation
@@ -0,0 +1,10 @@
+# Expectations for preparser tests.
+# Only mentions tests that throw SyntaxError, and optionally specifies
+# the message and location expected in the exception.
+# Format:
+# testname[:message[:beg_pos,end_pos]]
+strict-octal-number:strict_octal_literal
+strict-octal-string:strict_octal_literal
+strict-octal-regexp:strict_octal_literal
+strict-octal-use-strict-after:strict_octal_literal
+strict-octal-use-strict-before:strict_octal_literal
diff --git a/test/preparser/preparser.status b/test/preparser/preparser.status
new file mode 100644
index 0000000..db17778
--- /dev/null
+++ b/test/preparser/preparser.status
@@ -0,0 +1,39 @@
+# 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.
+
+prefix preparser
+
+# We don't parse RegExps at scanning time, so we can't fail on octal
+# escapes (we need to parse to distinguish octal escapes from valid
+# back-references).
+strict-octal-regexp: FAIL
+
+##############################################################################
+[ $arch == mips ]
+
+# Skip all tests on MIPS.
+*: SKIP
diff --git a/test/preparser/strict-octal-indirect-regexp.js b/test/preparser/strict-octal-indirect-regexp.js
new file mode 100644
index 0000000..122bd3d
--- /dev/null
+++ b/test/preparser/strict-octal-indirect-regexp.js
@@ -0,0 +1,34 @@
+// 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.
+
+// Strict mode with call to RegExp containing octal escape:
+
+function foo() {
+ "use strict";
+ var re = RegExp("Hello\\040World");
+ return re;
+}
\ No newline at end of file
diff --git a/test/preparser/strict-octal-number.js b/test/preparser/strict-octal-number.js
new file mode 100644
index 0000000..d387d6a
--- /dev/null
+++ b/test/preparser/strict-octal-number.js
@@ -0,0 +1,34 @@
+// 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.
+
+// Strict mode with octal number literal.
+
+function foo() {
+ "use strict";
+ var x = 012;
+ return x;
+}
\ No newline at end of file
diff --git a/test/preparser/strict-octal-regexp.js b/test/preparser/strict-octal-regexp.js
new file mode 100644
index 0000000..fded9bf
--- /dev/null
+++ b/test/preparser/strict-octal-regexp.js
@@ -0,0 +1,34 @@
+// 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.
+
+// Strict mode with octal escape in RegExp literal.
+
+function foo() {
+ "use strict";
+ var re = /hello\040world/;
+ return re;
+}
\ No newline at end of file
diff --git a/test/preparser/strict-octal-string.js b/test/preparser/strict-octal-string.js
new file mode 100644
index 0000000..40408e6
--- /dev/null
+++ b/test/preparser/strict-octal-string.js
@@ -0,0 +1,34 @@
+// 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.
+
+// Strict mode with octal escape in string literal.
+
+function foo() {
+ "use strict";
+ var x = "hello\040world";
+ return x;
+}
\ No newline at end of file
diff --git a/test/preparser/strict-octal-use-strict-after.js b/test/preparser/strict-octal-use-strict-after.js
new file mode 100644
index 0000000..1af078a
--- /dev/null
+++ b/test/preparser/strict-octal-use-strict-after.js
@@ -0,0 +1,35 @@
+// 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.
+
+// Strict mode with octal escape in string/directive prologue looking like
+// "use strict", after "use strict" directive.
+
+function foo() {
+ "use strict";
+ "use\040strict";
+ return true;
+}
\ No newline at end of file
diff --git a/test/preparser/strict-octal-use-strict-before.js b/test/preparser/strict-octal-use-strict-before.js
new file mode 100644
index 0000000..1dbb571
--- /dev/null
+++ b/test/preparser/strict-octal-use-strict-before.js
@@ -0,0 +1,35 @@
+// 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.
+
+// Strict mode with octal escape in string/directive prologue looking like
+// "use strict, before "use strict" directive.
+
+function foo() {
+ "use\040strict";
+ "use strict";
+ return true;
+}
\ No newline at end of file