Upgrade to V8 3.6
Merge V8 at 3.6.6.11
Simple merge required updates to makefiles only.
Bug: 5688872
Change-Id: Ib38b7ffbcd409585f6cb6fccc59c767029cecc77
diff --git a/.gitignore b/.gitignore
index 253639d..b61faef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,18 @@
*.a
*.exe
+*.idb
*.lib
*.log
*.map
*.mk
*.ncb
+*.pdb
*.pyc
*.scons*
+*.so
*.suo
*.user
*.xcodeproj
-*.idb
-*.pdb
#*#
*~
.cpplint-cache
diff --git a/AUTHORS b/AUTHORS
index d4e35fe..fcb5c20 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,6 +21,7 @@
Daniel James <dnljms@gmail.com>
Dineel D Sule <dsule@codeaurora.org>
Erich Ocean <erich.ocean@me.com>
+Fedor Indutny <fedor@indutny.com>
Jan de Mooij <jandemooij@gmail.com>
Jay Freeman <saurik@saurik.com>
Joel Stanley <joel.stan@gmail.com>
diff --git a/Android.libv8.mk b/Android.libv8.mk
index 96d632e..512d271 100644
--- a/Android.libv8.mk
+++ b/Android.libv8.mk
@@ -16,7 +16,7 @@
# and V8_LOCAL_JS_LIBRARY_FILES
V8_LOCAL_SRC_FILES :=
V8_LOCAL_JS_LIBRARY_FILES :=
-V8_LOCAL_EXPERIMENTAL_JS_LIBRARY_FILES :=
+V8_LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES :=
include $(LOCAL_PATH)/Android.v8common.mk
# Target can only be linux
@@ -27,7 +27,7 @@
LOCAL_SRC_FILES := $(V8_LOCAL_SRC_FILES)
LOCAL_JS_LIBRARY_FILES := $(addprefix $(LOCAL_PATH)/, $(V8_LOCAL_JS_LIBRARY_FILES))
-LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES := $(addprefix $(LOCAL_PATH)/, $(V8_LOCAL_EXPERIMENTAL_JS_LIBRARY_FILES))
+LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES := $(addprefix $(LOCAL_PATH)/, $(V8_LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES))
# Copy js2c.py to intermediates directory and invoke there to avoid generating
# jsmin.pyc in the source directory
diff --git a/Android.mksnapshot.mk b/Android.mksnapshot.mk
index 07da14b..c1ffcea 100644
--- a/Android.mksnapshot.mk
+++ b/Android.mksnapshot.mk
@@ -34,7 +34,7 @@
LOCAL_SRC_FILES := $(V8_LOCAL_SRC_FILES)
LOCAL_JS_LIBRARY_FILES := $(addprefix $(LOCAL_PATH)/, $(V8_LOCAL_JS_LIBRARY_FILES))
-LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES := $(addprefix $(LOCAL_PATH)/, $(V8_LOCAL_EXPERIMENTAL_JS_LIBRARY_FILES))
+LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES := $(addprefix $(LOCAL_PATH)/, $(V8_LOCAL_JS_EXPERIMENTAL_LIBRARY_FILES))
# Copy js2c.py to intermediates directory and invoke there to avoid generating
# jsmin.pyc in the source directory
diff --git a/Android.v8common.mk b/Android.v8common.mk
index cb64a81..2012573 100644
--- a/Android.v8common.mk
+++ b/Android.v8common.mk
@@ -73,7 +73,7 @@
src/runtime-profiler.cc \
src/safepoint-table.cc \
src/scanner.cc \
- src/scanner-base.cc \
+ src/scanner-character-streams.cc \
src/scopeinfo.cc \
src/scopes.cc \
src/serialize.cc \
diff --git a/ChangeLog b/ChangeLog
index 02d0ebb..99495dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,70 @@
+2011-09-15: Version 3.6.4
+
+ Fixed d8's broken readline history.
+
+ Removed the need for code delete events in CPU profiler (Issue 1466).
+
+ Fixed debugger stepping next with trycatch recursion (Issue 1639).
+
+ Fixing parallel execution in d8 (with -p) and some memory leaks.
+
+ Support for precise stepping in functions compiled before debugging was
+ started (step 1).
+
+
+2011-09-13: Version 3.6.3
+
+ Implemented better support of typed arrays in the d8 shell.
+
+ Bug fixes and performance improvements on all platforms.
+
+
+2011-09-08: Version 3.6.2
+
+ Added "dependencies" target to top-level Makefile.
+
+ Added ability to turn profiler on/off in d8.
+
+ Added "soname_version" parameter to common.gypi, v8.gyp, and Makefile.
+
+ Fixed several crash bugs.
+
+
+2011-09-07: Version 3.6.1
+
+ Fixed a bug in abrupt exit from with or catch inside finally.
+
+ Fixed possible crash in FixedDoubleArray::Initialize() (Chromium
+ issue 95113).
+
+ Fixed a bug in Page::GetRegionMaskForSpan (Chromium issue 94425).
+
+ Fixed a few clang warnings (which -Werror treated as errors).
+
+ Performance improvements on all platforms.
+
+
+2011-09-05: Version 3.6.0
+
+ Fixed a bug when optimizing named function expression (issue 1647).
+
+ Fixed a bug when optimizing f.call.apply (issue 1650).
+
+ Made arguments and caller always be null on native functions
+ (issues 1548 and 1643).
+
+ Fixed issue 1648 (cross-compiling x64 targeting ia32).
+
+ Fixed issue 371 (d8 printing of strings containing \0).
+
+ Fixed order of evaluation in arguments to parseInt (issue 1649).
+
+ Fixed a problem with large heap snapshots in Chrome DevTools
+ (issue 1658, chromium issue 89268).
+
+ Upped default maximum heap size from 512M to 700M.
+
+
2011-08-31: Version 3.5.10
Added dependency of v8_base on WinSocket2 Windows library in
diff --git a/Makefile b/Makefile
index 3008779..a7b2731 100644
--- a/Makefile
+++ b/Makefile
@@ -68,8 +68,13 @@
else
GYPFLAGS += -Dv8_can_use_vfp_instructions=true
endif
+# soname_version=1.2.3
+ifdef soname_version
+ GYPFLAGS += -Dsoname_version=$(soname_version)
+endif
# ----------------- available targets: --------------------
+# - "dependencies": pulls in external dependencies (currently: GYP)
# - any arch listed in ARCHES (see below)
# - any mode listed in MODES
# - every combination <arch>.<mode>, e.g. "ia32.release"
@@ -98,8 +103,9 @@
# File where previously used GYPFLAGS are stored.
ENVFILE = $(OUTDIR)/environment
-.PHONY: all clean $(ENVFILE).new \
- $(ARCHES) $(MODES) $(BUILDS) $(addsuffix .clean,$(ARCHES))
+.PHONY: all check clean dependencies $(ENVFILE).new \
+ $(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \
+ $(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES))
# Target definitions. "all" is the default.
all: $(MODES)
@@ -169,3 +175,8 @@
# Stores current GYPFLAGS in a file.
$(ENVFILE).new:
@mkdir -p $(OUTDIR); echo "GYPFLAGS=$(GYPFLAGS)" > $(ENVFILE).new;
+
+# Dependencies.
+dependencies:
+ svn checkout --force http://gyp.googlecode.com/svn/trunk build/gyp \
+ --revision 1026
diff --git a/V8_MERGE_REVISION b/V8_MERGE_REVISION
index 8caa544..e342771 100644
--- a/V8_MERGE_REVISION
+++ b/V8_MERGE_REVISION
@@ -1,2 +1,2 @@
-V8 3.5.10.24
-http://v8.googlecode.com/svn/branches/3.5@9918
+V8 3.6.6.11
+http://v8.googlecode.com/svn/branches/3.6@10120
diff --git a/benchmarks/crypto.js b/benchmarks/crypto.js
index ffa69b5..531ad45 100644
--- a/benchmarks/crypto.js
+++ b/benchmarks/crypto.js
@@ -1406,7 +1406,7 @@
// Mix in the current time (w/milliseconds) into the pool
function rng_seed_time() {
- // Use pre-computed date to avoid making the benchmark
+ // Use pre-computed date to avoid making the benchmark
// results dependent on the current date.
rng_seed_int(1122926989487);
}
diff --git a/benchmarks/earley-boyer.js b/benchmarks/earley-boyer.js
index 1be480e..b2328d6 100644
--- a/benchmarks/earley-boyer.js
+++ b/benchmarks/earley-boyer.js
@@ -134,7 +134,7 @@
/*** META ((export #t)) */
function sc_any2String(o) {
return jsstring2string(sc_toDisplayString(o));
-}
+}
/*** META ((export #t)
(peephole (infix 2 2 "==="))
@@ -923,7 +923,7 @@
tmp.cdr = l2;
return l1;
}
-
+
/*** META ((export #t)) */
function sc_appendBang() {
var res = null;
@@ -1163,7 +1163,7 @@
"us": "\037",
"sp": "\040",
"del": "\177"};
-
+
sc_Char.prototype.toString = function() {
return this.val;
};
@@ -1533,7 +1533,7 @@
}
return l1_orig;
}
-
+
/*** META ((export #t)) */
function sc_forEach(proc, l1) {
if (l1 === undefined)
@@ -1871,7 +1871,7 @@
evalStr += ", arguments[" + i + "]";
evalStr +=")";
return eval(evalStr);
-}
+}
// ======================== RegExp ====================
/*** META ((export #t)) */
@@ -1883,9 +1883,9 @@
function sc_pregexpMatch(re, s) {
var reg = (re instanceof RegExp) ? re : sc_pregexp(re);
var tmp = reg.exec(sc_string2jsstring(s));
-
+
if (tmp == null) return false;
-
+
var res = null;
for (var i = tmp.length-1; i >= 0; i--) {
if (tmp[i] !== null) {
@@ -1896,7 +1896,7 @@
}
return res;
}
-
+
/*** META ((export #t)) */
function sc_pregexpReplace(re, s1, s2) {
var reg;
@@ -1914,7 +1914,7 @@
return jss1.replace(reg, jss2);
}
-
+
/*** META ((export pregexp-replace*)) */
function sc_pregexpReplaceAll(re, s1, s2) {
var reg;
@@ -1945,7 +1945,7 @@
return sc_vector2list(tmp);
}
-
+
/* =========================================================================== */
/* Other library stuff */
@@ -2136,7 +2136,7 @@
sc_ErrorInputPort.prototype.isCharReady = function() {
return false;
};
-
+
/* .............. String port ..........................*/
@@ -2200,7 +2200,7 @@
};
sc_Tokenizer.prototype.nextToken = function() {
var port = this.port;
-
+
function isNumberChar(c) {
return (c >= "0" && c <= "9");
};
@@ -2280,7 +2280,7 @@
else
return new sc_Token(12/*NUMBER*/, res - 0);
};
-
+
function skipWhitespaceAndComments() {
var done = false;
while (!done) {
@@ -2299,7 +2299,7 @@
}
}
};
-
+
function readDot() {
if (isWhitespace(port.peekChar()))
return new sc_Token(10/*DOT*/);
@@ -2429,7 +2429,7 @@
while (true) {
var token = tokenizer.peekToken();
-
+
switch (token.type) {
case 2/*CLOSE_PAR*/:
case 4/*CLOSE_BRACE*/:
@@ -2491,7 +2491,7 @@
else
throw "bad reference: " + nb;
};
-
+
var tokenizer = this.tokenizer;
var token = tokenizer.readToken();
@@ -2499,7 +2499,7 @@
// handle error
if (token.type === 13/*ERROR*/)
throw token.val;
-
+
switch (token.type) {
case 1/*OPEN_PAR*/:
case 3/*OPEN_BRACE*/:
@@ -2550,7 +2550,7 @@
port = SC_DEFAULT_IN; // THREAD: shared var...
var t = port.peekChar();
return t === SC_EOF_OBJECT? t: new sc_Char(t);
-}
+}
/*** META ((export #t)
(type bool))
*/
@@ -2722,7 +2722,7 @@
function sc_getOutputString(sp) {
return sc_jsstring2string(sp.res);
}
-
+
function sc_ErrorOutputPort() {
}
@@ -2852,7 +2852,7 @@
p = SC_DEFAULT_OUT;
p.appendJSString("\n");
}
-
+
/* ------------------ write-char ---------------------------------------------------*/
/*** META ((export #t)) */
@@ -2927,7 +2927,7 @@
}
var res = "";
-
+
if (this[symb] !== undefined) { // implies > 0
this[symb + "use"] = true;
if (inList)
@@ -2939,10 +2939,10 @@
if (!inList)
res += "(";
-
+
// print car
res += sc_genToWriteCircleString(this.car, symb);
-
+
if (sc_isPair(this.cdr)) {
res += " " + this.cdr.sc_toWriteCircleString(symb, true);
} else if (this.cdr !== null) {
@@ -3072,7 +3072,7 @@
p.appendJSString(arguments[j].toString(2));
i += 2; j++;
break;
-
+
case 37:
case 110:
// %, n
@@ -3186,7 +3186,7 @@
function sc_number2symbol(x, radix) {
return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix);
}
-
+
/*** META ((export number->string integer->string)) */
var sc_number2string = sc_number2jsstring;
diff --git a/benchmarks/regexp.js b/benchmarks/regexp.js
index 71b9e63..9c83142 100644
--- a/benchmarks/regexp.js
+++ b/benchmarks/regexp.js
@@ -33,7 +33,7 @@
// the popularity of the pages where it occurs and the number of times
// it is executed while loading each page. Furthermore the literal
// letters in the data are encoded using ROT13 in a way that does not
-// affect how the regexps match their input. Finally the strings are
+// affect how the regexps match their input. Finally the strings are
// scrambled to exercise the regexp engine on different input strings.
@@ -47,7 +47,7 @@
regExpBenchmark = new RegExpBenchmark();
RegExpRun(); // run once to get system initialized
}
-
+
function RegExpRun() {
regExpBenchmark.run();
}
@@ -1759,6 +1759,6 @@
runBlock11();
}
}
-
+
this.run = run;
}
diff --git a/build/README.txt b/build/README.txt
index c74b520..ea6287f 100644
--- a/build/README.txt
+++ b/build/README.txt
@@ -53,11 +53,11 @@
> svn co http://src.chromium.org/svn/trunk/deps/third_party/cygwin@66844 third_party/cygwin
-To run GYP Python is required and it is reccomended to use the same version as
+To run GYP Python is required and it is recommended to use the same version as
is used by the Chromium project. This can also be checked out from the Chromium
repository. From the root of the V8 project do the following:
-> svn co http://src.chromium.org/svn/trunk/tools/third_party/python_26@70627 third_party/python_26
+> svn co http://src.chromium.org/svn/trunk/tools/third_party/python_26@89111 third_party/python_26
Now generate Visual Studio solution and project files for the ia32 architecture:
diff --git a/build/all.gyp b/build/all.gyp
index 9c0f05c..4b2fe52 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -1,4 +1,4 @@
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Copyright 2011 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -11,13 +11,7 @@
'../preparser/preparser.gyp:*',
'../samples/samples.gyp:*',
'../src/d8.gyp:d8',
- ],
- 'conditions': [
- [ 'component!="shared_library"', {
- 'dependencies': [
- '../test/cctest/cctest.gyp:*',
- ],
- }]
+ '../test/cctest/cctest.gyp:*',
],
}
]
diff --git a/build/common.gypi b/build/common.gypi
index 834516f..4e896e0 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -72,6 +72,9 @@
'v8_use_snapshot%': 'true',
'host_os%': '<(OS)',
'v8_use_liveobjectlist%': 'false',
+
+ # For a shared library build, results in "libv8-<(soname_version).so".
+ 'soname_version%': '',
},
'target_defaults': {
'conditions': [
@@ -173,6 +176,14 @@
},
},
}],
+ ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
+ 'conditions': [
+ [ 'target_arch=="ia32"', {
+ 'cflags': [ '-m32' ],
+ 'ldflags': [ '-m32' ],
+ }],
+ ],
+ }],
],
'configurations': {
'Debug': {
diff --git a/build/standalone.gypi b/build/standalone.gypi
index 81909f1..cb5e133 100644
--- a/build/standalone.gypi
+++ b/build/standalone.gypi
@@ -79,10 +79,6 @@
'-fno-exceptions', '-pedantic' ],
'ldflags': [ '-pthread', ],
'conditions': [
- [ 'target_arch=="ia32"', {
- 'cflags': [ '-m32' ],
- 'ldflags': [ '-m32' ],
- }],
[ 'OS=="linux"', {
'cflags': [ '-ansi' ],
}],
diff --git a/include/v8.h b/include/v8.h
index 5a78160..4b7f6e7 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1051,18 +1051,21 @@
NO_NULL_TERMINATION = 2
};
+ // 16-bit character codes.
V8EXPORT int Write(uint16_t* buffer,
int start = 0,
int length = -1,
- int options = NO_OPTIONS) const; // UTF-16
+ int options = NO_OPTIONS) const;
+ // ASCII characters.
V8EXPORT int WriteAscii(char* buffer,
int start = 0,
int length = -1,
- int options = NO_OPTIONS) const; // ASCII
+ int options = NO_OPTIONS) const;
+ // UTF-8 encoded characters.
V8EXPORT int WriteUtf8(char* buffer,
int length = -1,
int* nchars_ref = NULL,
- int options = NO_OPTIONS) const; // UTF-8
+ int options = NO_OPTIONS) const;
/**
* A zero length string.
@@ -1075,7 +1078,7 @@
V8EXPORT bool IsExternal() const;
/**
- * Returns true if the string is both external and ascii
+ * Returns true if the string is both external and ASCII
*/
V8EXPORT bool IsExternalAscii() const;
@@ -1132,11 +1135,11 @@
};
/**
- * An ExternalAsciiStringResource is a wrapper around an ascii
+ * An ExternalAsciiStringResource is a wrapper around an ASCII
* string buffer that resides outside V8's heap. Implement an
* ExternalAsciiStringResource to manage the life cycle of the
* underlying buffer. Note that the string data must be immutable
- * and that the data must be strict 7-bit ASCII, not Latin1 or
+ * and that the data must be strict (7-bit) ASCII, not Latin-1 or
* UTF-8, which would require special treatment internally in the
* engine and, in the case of UTF-8, do not allow efficient indexing.
* Use String::New or convert to 16 bit data for non-ASCII.
@@ -1152,7 +1155,7 @@
virtual ~ExternalAsciiStringResource() {}
/** The string data from the underlying buffer.*/
virtual const char* data() const = 0;
- /** The number of ascii characters in the string.*/
+ /** The number of ASCII characters in the string.*/
virtual size_t length() const = 0;
protected:
ExternalAsciiStringResource() {}
@@ -1165,7 +1168,7 @@
inline ExternalStringResource* GetExternalStringResource() const;
/**
- * Get the ExternalAsciiStringResource for an external ascii string.
+ * Get the ExternalAsciiStringResource for an external ASCII string.
* Returns NULL if IsExternalAscii() doesn't return true.
*/
V8EXPORT ExternalAsciiStringResource* GetExternalAsciiStringResource() const;
@@ -1173,9 +1176,9 @@
static inline String* Cast(v8::Value* obj);
/**
- * Allocates a new string from either utf-8 encoded or ascii data.
+ * Allocates a new string from either UTF-8 encoded or ASCII data.
* The second parameter 'length' gives the buffer length.
- * If the data is utf-8 encoded, the caller must
+ * If the data is UTF-8 encoded, the caller must
* be careful to supply the length parameter.
* If it is not given, the function calls
* 'strlen' to determine the buffer length, it might be
@@ -1183,7 +1186,7 @@
*/
V8EXPORT static Local<String> New(const char* data, int length = -1);
- /** Allocates a new string from utf16 data.*/
+ /** Allocates a new string from 16-bit character codes.*/
V8EXPORT static Local<String> New(const uint16_t* data, int length = -1);
/** Creates a symbol. Returns one if it exists already.*/
@@ -1218,7 +1221,7 @@
V8EXPORT bool MakeExternal(ExternalStringResource* resource);
/**
- * Creates a new external string using the ascii data defined in the given
+ * Creates a new external string using the ASCII data defined in the given
* resource. When the external string is no longer live on V8's heap the
* resource will be disposed by calling its Dispose method. The caller of
* this function should not otherwise delete or modify the resource. Neither
@@ -1244,18 +1247,18 @@
*/
V8EXPORT bool CanMakeExternal();
- /** Creates an undetectable string from the supplied ascii or utf-8 data.*/
+ /** Creates an undetectable string from the supplied ASCII or UTF-8 data.*/
V8EXPORT static Local<String> NewUndetectable(const char* data,
int length = -1);
- /** Creates an undetectable string from the supplied utf-16 data.*/
+ /** Creates an undetectable string from the supplied 16-bit character codes.*/
V8EXPORT static Local<String> NewUndetectable(const uint16_t* data,
int length = -1);
/**
- * Converts an object to a utf8-encoded character array. Useful if
+ * Converts an object to a UTF-8-encoded character array. Useful if
* you want to print the object. If conversion to a string fails
- * (eg. due to an exception in the toString() method of the object)
+ * (e.g. due to an exception in the toString() method of the object)
* then the length() method returns 0 and the * operator returns
* NULL.
*/
@@ -1276,7 +1279,7 @@
};
/**
- * Converts an object to an ascii string.
+ * Converts an object to an ASCII string.
* Useful if you want to print the object.
* If conversion to a string fails (eg. due to an exception in the toString()
* method of the object) then the length() method returns 0 and the * operator
@@ -1656,7 +1659,7 @@
V8EXPORT bool IsCallable();
/**
- * Call an Object as a function if a callback is set by the
+ * Call an Object as a function if a callback is set by the
* ObjectTemplate::SetCallAsFunctionHandler method.
*/
V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv,
@@ -3562,7 +3565,7 @@
* // V8 Now no longer locked.
* \endcode
*
- *
+ *
*/
class V8EXPORT Unlocker {
public:
diff --git a/samples/process.cc b/samples/process.cc
index 07c4805..c0cee4c 100644
--- a/samples/process.cc
+++ b/samples/process.cc
@@ -77,7 +77,6 @@
*/
class JsHttpRequestProcessor : public HttpRequestProcessor {
public:
-
// Creates a new processor that processes requests by invoking the
// Process function of the JavaScript script given as an argument.
explicit JsHttpRequestProcessor(Handle<String> script) : script_(script) { }
@@ -88,7 +87,6 @@
virtual bool Process(HttpRequest* req);
private:
-
// Execute the script associated with this processor and extract the
// Process function. Returns true if this succeeded, otherwise false.
bool ExecuteScript(Handle<String> script);
diff --git a/samples/shell.cc b/samples/shell.cc
index 8ed9d03..b40eca2 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -250,16 +250,14 @@
static const int kBufferSize = 256;
// Enter the execution environment before evaluating any code.
v8::Context::Scope context_scope(context);
+ v8::Local<v8::String> name(v8::String::New("(shell)"));
while (true) {
char buffer[kBufferSize];
printf("> ");
char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break;
v8::HandleScope handle_scope;
- ExecuteString(v8::String::New(str),
- v8::String::New("(shell)"),
- true,
- true);
+ ExecuteString(v8::String::New(str), name, true, true);
}
printf("\n");
}
diff --git a/src/SConscript b/src/SConscript
index 453a7c6..52607f1 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -111,8 +111,8 @@
runtime.cc
runtime-profiler.cc
safepoint-table.cc
- scanner-base.cc
scanner.cc
+ scanner-character-streams.cc
scopeinfo.cc
scopes.cc
serialize.cc
@@ -222,7 +222,7 @@
'os:solaris': ['platform-solaris.cc', 'platform-posix.cc'],
'os:cygwin': ['platform-cygwin.cc', 'platform-posix.cc'],
'os:nullos': ['platform-nullos.cc'],
- 'os:win32': ['platform-win32.cc'],
+ 'os:win32': ['platform-win32.cc', 'win32-math.cc'],
'mode:release': [],
'mode:debug': [
'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
@@ -233,15 +233,25 @@
PREPARSER_SOURCES = {
'all': Split("""
allocation.cc
+ bignum.cc
+ bignum-dtoa.cc
+ cached-powers.cc
+ conversions.cc
+ diy-fp.cc
+ dtoa.cc
+ fast-dtoa.cc
+ fixed-dtoa.cc
hashmap.cc
preparse-data.cc
preparser.cc
preparser-api.cc
- scanner-base.cc
+ scanner.cc
+ strtod.cc
token.cc
unicode.cc
utils.cc
- """)
+ """),
+ 'os:win32': ['win32-math.cc']
}
diff --git a/src/accessors.cc b/src/accessors.cc
index e7d6aa0..951209d 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -599,6 +599,7 @@
if (!found_it) return isolate->heap()->undefined_value();
Handle<JSFunction> function(holder, isolate);
+ if (function->shared()->native()) return isolate->heap()->null_value();
// Find the top invocation of the function by traversing frames.
List<JSFunction*> functions(2);
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
@@ -709,6 +710,7 @@
} while (next_function != NULL);
return false;
}
+
private:
void GetFunctions() {
functions_.Rewind(0);
@@ -732,6 +734,7 @@
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return isolate->heap()->undefined_value();
+ if (holder->shared()->native()) return isolate->heap()->null_value();
Handle<JSFunction> function(holder, isolate);
FrameFunctionIterator it(isolate, no_alloc);
diff --git a/src/api.cc b/src/api.cc
index 5bda725..479be5a 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -44,6 +44,7 @@
#include "platform.h"
#include "profile-generator-inl.h"
#include "runtime-profiler.h"
+#include "scanner-character-streams.h"
#include "serialize.h"
#include "snapshot.h"
#include "v8threads.h"
@@ -3265,6 +3266,42 @@
namespace {
+static i::ElementsKind GetElementsKindFromExternalArrayType(
+ ExternalArrayType array_type) {
+ switch (array_type) {
+ case kExternalByteArray:
+ return i::EXTERNAL_BYTE_ELEMENTS;
+ break;
+ case kExternalUnsignedByteArray:
+ return i::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
+ break;
+ case kExternalShortArray:
+ return i::EXTERNAL_SHORT_ELEMENTS;
+ break;
+ case kExternalUnsignedShortArray:
+ return i::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
+ break;
+ case kExternalIntArray:
+ return i::EXTERNAL_INT_ELEMENTS;
+ break;
+ case kExternalUnsignedIntArray:
+ return i::EXTERNAL_UNSIGNED_INT_ELEMENTS;
+ break;
+ case kExternalFloatArray:
+ return i::EXTERNAL_FLOAT_ELEMENTS;
+ break;
+ case kExternalDoubleArray:
+ return i::EXTERNAL_DOUBLE_ELEMENTS;
+ break;
+ case kExternalPixelArray:
+ return i::EXTERNAL_PIXEL_ELEMENTS;
+ break;
+ }
+ UNREACHABLE();
+ return i::DICTIONARY_ELEMENTS;
+}
+
+
void PrepareExternalArrayElements(i::Handle<i::JSObject> object,
void* data,
ExternalArrayType array_type,
@@ -3283,9 +3320,9 @@
elements->map() != isolate->heap()->MapForExternalArrayType(array_type);
if (cant_reuse_map) {
i::Handle<i::Map> external_array_map =
- isolate->factory()->GetExternalArrayElementsMap(
+ isolate->factory()->GetElementsTransitionMap(
i::Handle<i::Map>(object->map()),
- array_type,
+ GetElementsKindFromExternalArrayType(array_type),
object->HasFastProperties());
object->set_map(*external_array_map);
}
@@ -3347,6 +3384,7 @@
}
}
+
void v8::Object::SetIndexedPropertiesToExternalArrayData(
void* data,
ExternalArrayType array_type,
diff --git a/src/arguments.h b/src/arguments.h
index 72bbe1d..e9a3270 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -75,6 +75,7 @@
int length() const { return length_; }
Object** arguments() { return arguments_; }
+
private:
int length_;
Object** arguments_;
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index a35380c..60d2081 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -1230,16 +1230,17 @@
// 2. Get the function to call (passed as receiver) from the stack, check
// if it is a function.
// r0: actual number of arguments
- Label non_function;
+ Label slow, non_function;
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ JumpIfSmi(r1, &non_function);
__ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
- __ b(ne, &non_function);
+ __ b(ne, &slow);
// 3a. Patch the first argument if necessary when calling a function.
// r0: actual number of arguments
// r1: function
Label shift_arguments;
+ __ mov(r4, Operand(0, RelocInfo::NONE)); // indicate regular JS_FUNCTION
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
@@ -1286,8 +1287,9 @@
__ pop(r0);
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
__ LeaveInternalFrame();
- // Restore the function to r1.
+ // Restore the function to r1, and the flag to r4.
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
+ __ mov(r4, Operand(0, RelocInfo::NONE));
__ jmp(&patch_receiver);
// Use the global receiver object from the called function as the
@@ -1307,23 +1309,30 @@
__ jmp(&shift_arguments);
}
- // 3b. Patch the first argument when calling a non-function. The
+ // 3b. Check for function proxy.
+ __ bind(&slow);
+ __ mov(r4, Operand(1, RelocInfo::NONE)); // indicate function proxy
+ __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
+ __ b(eq, &shift_arguments);
+ __ bind(&non_function);
+ __ mov(r4, Operand(2, RelocInfo::NONE)); // indicate non-function
+
+ // 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
// receiver, so overwrite the first argument which will ultimately
// become the receiver.
// r0: actual number of arguments
// r1: function
- __ bind(&non_function);
+ // r4: call type (0: JS function, 1: function proxy, 2: non-function)
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
__ str(r1, MemOperand(r2, -kPointerSize));
- // Clear r1 to indicate a non-function being called.
- __ mov(r1, Operand(0, RelocInfo::NONE));
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
// the original first argument the new receiver.
// r0: actual number of arguments
// r1: function
+ // r4: call type (0: JS function, 1: function proxy, 2: non-function)
__ bind(&shift_arguments);
{ Label loop;
// Calculate the copy start address (destination). Copy end address is sp.
@@ -1341,16 +1350,28 @@
__ pop();
}
- // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
+ // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+ // or a function proxy via CALL_FUNCTION_PROXY.
// r0: actual number of arguments
// r1: function
- { Label function;
- __ tst(r1, r1);
- __ b(ne, &function);
+ // r4: call type (0: JS function, 1: function proxy, 2: non-function)
+ { Label function, non_proxy;
+ __ tst(r4, r4);
+ __ b(eq, &function);
// Expected number of arguments is 0 for CALL_NON_FUNCTION.
__ mov(r2, Operand(0, RelocInfo::NONE));
- __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(r5, CALL_AS_METHOD);
+ __ cmp(r4, Operand(1));
+ __ b(ne, &non_proxy);
+
+ __ push(r1); // re-add proxy object as additional argument
+ __ add(r0, r0, Operand(1));
+ __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ bind(&non_proxy);
+ __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
@@ -1393,7 +1414,7 @@
__ push(r0);
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow. We are not trying need to catch
+ // Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
@@ -1418,18 +1439,24 @@
__ mov(r1, Operand(0, RelocInfo::NONE)); // initial index
__ push(r1);
- // Change context eagerly to get the right global object if necessary.
- __ ldr(r0, MemOperand(fp, kFunctionOffset));
- __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
- // Load the shared function info while the function is still in r0.
- __ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
-
- // Compute the receiver.
- Label call_to_object, use_global_receiver, push_receiver;
+ // Get the receiver.
__ ldr(r0, MemOperand(fp, kRecvOffset));
+ // Check that the function is a JS function (otherwise it must be a proxy).
+ Label push_receiver;
+ __ ldr(r1, MemOperand(fp, kFunctionOffset));
+ __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+ __ b(ne, &push_receiver);
+
+ // Change context eagerly to get the right global object if necessary.
+ __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
+ // Load the shared function info while the function is still in r1.
+ __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+
+ // Compute the receiver.
// Do not transform the receiver for strict mode functions.
- __ ldr(r2, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
+ Label call_to_object, use_global_receiver;
+ __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCompilerHintsOffset));
__ tst(r2, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
kSmiTagSize)));
__ b(ne, &push_receiver);
@@ -1504,9 +1531,12 @@
__ b(ne, &loop);
// Invoke the function.
+ Label call_proxy;
ParameterCount actual(r0);
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
__ ldr(r1, MemOperand(fp, kFunctionOffset));
+ __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+ __ b(ne, &call_proxy);
__ InvokeFunction(r1, actual, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
@@ -1514,6 +1544,20 @@
__ LeaveInternalFrame();
__ add(sp, sp, Operand(3 * kPointerSize));
__ Jump(lr);
+
+ // Invoke the function proxy.
+ __ bind(&call_proxy);
+ __ push(r1); // add function proxy as last argument
+ __ add(r0, r0, Operand(1));
+ __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ SetCallKind(r5, CALL_AS_METHOD);
+ __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
+ __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ LeaveInternalFrame();
+ __ add(sp, sp, Operand(3 * kPointerSize));
+ __ Jump(lr);
}
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 09d2c17..e65f6d9 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -3432,7 +3432,7 @@
// Retrieve the pending exception and clear the variable.
__ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r3, MemOperand(ip));
- __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ ldr(r0, MemOperand(ip));
__ str(r3, MemOperand(ip));
@@ -3567,7 +3567,7 @@
__ mov(r7, Operand(Smi::FromInt(marker)));
__ mov(r6, Operand(Smi::FromInt(marker)));
__ mov(r5,
- Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate)));
+ Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
__ ldr(r5, MemOperand(r5));
__ Push(r8, r7, r6, r5);
@@ -3576,7 +3576,7 @@
// If this is the outermost JS call, set js_entry_sp value.
Label non_outermost_js;
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate);
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
__ mov(r5, Operand(ExternalReference(js_entry_sp)));
__ ldr(r6, MemOperand(r5));
__ cmp(r6, Operand::Zero());
@@ -3597,7 +3597,7 @@
// exception field in the JSEnv and return a failure sentinel.
// Coming in here the fp will be invalid because the PushTryHandler below
// sets it to 0 to signal the existence of the JSEntry frame.
- __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ str(r0, MemOperand(ip));
__ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
@@ -3615,7 +3615,7 @@
// Clear any pending exceptions.
__ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r5, MemOperand(ip));
- __ mov(ip, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ str(r5, MemOperand(ip));
@@ -3662,7 +3662,7 @@
// Restore the top frame descriptors from the stack.
__ pop(r3);
__ mov(ip,
- Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate)));
+ Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate)));
__ str(r3, MemOperand(ip));
// Reset the stack to the callee saved registers.
@@ -4487,7 +4487,7 @@
// frame. Therefore we have to use fp, which points exactly to two pointer
// sizes below the previous sp. (Because creating a new stack frame pushes
// the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
- __ ldr(r0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
+ __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
// If slice offset is not 0, load the length from the original sliced string.
// Argument 4, r3: End of string data
// Argument 3, r2: Start of string data
@@ -4495,7 +4495,7 @@
__ add(r9, r8, Operand(r9, LSL, r3));
__ add(r2, r9, Operand(r1, LSL, r3));
- __ ldr(r8, FieldMemOperand(r0, String::kLengthOffset));
+ __ ldr(r8, FieldMemOperand(subject, String::kLengthOffset));
__ mov(r8, Operand(r8, ASR, kSmiTagSize));
__ add(r3, r9, Operand(r8, LSL, r3));
@@ -4503,7 +4503,7 @@
// Already there
// Argument 1 (r0): Subject string.
- // Already there
+ __ mov(r0, subject);
// Locate the code entry and call it.
__ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
@@ -4520,12 +4520,12 @@
// Check the result.
Label success;
- __ cmp(subject, Operand(NativeRegExpMacroAssembler::SUCCESS));
+ __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS));
__ b(eq, &success);
Label failure;
- __ cmp(subject, Operand(NativeRegExpMacroAssembler::FAILURE));
+ __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE));
__ b(eq, &failure);
- __ cmp(subject, Operand(NativeRegExpMacroAssembler::EXCEPTION));
+ __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
// If not exception it can only be retry. Handle that in the runtime system.
__ b(ne, &runtime);
// Result must now be exception. If there is no pending exception already a
@@ -4534,21 +4534,21 @@
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
__ mov(r1, Operand(ExternalReference::the_hole_value_location(isolate)));
__ ldr(r1, MemOperand(r1, 0));
- __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ ldr(r0, MemOperand(r2, 0));
- __ cmp(subject, r1);
+ __ cmp(r0, r1);
__ b(eq, &runtime);
__ str(r1, MemOperand(r2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
- __ LoadRoot(ip, Heap::kTerminationExceptionRootIndex);
- __ cmp(subject, ip);
+ __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
+
Label termination_exception;
__ b(eq, &termination_exception);
- __ Throw(subject); // Expects thrown value in r0.
+ __ Throw(r0); // Expects thrown value in r0.
__ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0.
@@ -4713,7 +4713,7 @@
void CallFunctionStub::Generate(MacroAssembler* masm) {
- Label slow;
+ Label slow, non_function;
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
@@ -4739,7 +4739,7 @@
// Check that the function is really a JavaScript function.
// r1: pushed function (to be verified)
- __ JumpIfSmi(r1, &slow);
+ __ JumpIfSmi(r1, &non_function);
// Get the map of the function object.
__ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
__ b(ne, &slow);
@@ -4767,8 +4767,23 @@
// Slow-case: Non-function called.
__ bind(&slow);
+ // Check for function proxy.
+ __ cmp(r2, Operand(JS_FUNCTION_PROXY_TYPE));
+ __ b(ne, &non_function);
+ __ push(r1); // put proxy as additional argument
+ __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE));
+ __ mov(r2, Operand(0, RelocInfo::NONE));
+ __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
+ __ SetCallKind(r5, CALL_AS_FUNCTION);
+ {
+ Handle<Code> adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ Jump(adaptor, RelocInfo::CODE_TARGET);
+ }
+
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
+ __ bind(&non_function);
__ str(r1, MemOperand(sp, argc_ * kPointerSize));
__ mov(r0, Operand(argc_)); // Setup the number of arguments.
__ mov(r2, Operand(0, RelocInfo::NONE));
@@ -4894,7 +4909,8 @@
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ tst(result_, Operand(kStringEncodingMask));
__ b(ne, &ascii_string);
@@ -5468,11 +5484,6 @@
Register to = r6;
Register from = r7;
- if (FLAG_string_slices) {
- __ nop(0); // Jumping as first instruction would crash the code generation.
- __ jmp(&runtime);
- }
-
__ Ldrd(to, from, MemOperand(sp, kToOffset));
STATIC_ASSERT(kFromOffset == kToOffset + 4);
STATIC_ASSERT(kSmiTag == 0);
@@ -5490,64 +5501,79 @@
__ b(mi, &runtime); // Fail if from > to.
// Special handling of sub-strings of length 1 and 2. One character strings
// are handled in the runtime system (looked up in the single character
- // cache). Two character strings are looked for in the symbol cache.
+ // cache). Two character strings are looked for in the symbol cache in
+ // generated code.
__ cmp(r2, Operand(2));
__ b(lt, &runtime);
- // r2: length
- // r3: from index (untaged smi)
+ // r2: result string length
+ // r3: from index (untagged smi)
// r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi)
-
// Make sure first argument is a sequential (or flat) string.
- __ ldr(r5, MemOperand(sp, kStringOffset));
+ __ ldr(r0, MemOperand(sp, kStringOffset));
STATIC_ASSERT(kSmiTag == 0);
- __ JumpIfSmi(r5, &runtime);
- Condition is_string = masm->IsObjectStringType(r5, r1);
+ __ JumpIfSmi(r0, &runtime);
+ Condition is_string = masm->IsObjectStringType(r0, r1);
__ b(NegateCondition(is_string), &runtime);
+ // Short-cut for the case of trivial substring.
+ Label return_r0;
+ // r0: original string
+ // r2: result string length
+ __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
+ __ cmp(r2, Operand(r4, ASR, 1));
+ __ b(eq, &return_r0);
+
+ Label create_slice;
+ if (FLAG_string_slices) {
+ __ cmp(r2, Operand(SlicedString::kMinLength));
+ __ b(ge, &create_slice);
+ }
+
+ // r0: original string
// r1: instance type
- // r2: length
+ // r2: result string length
// r3: from index (untagged smi)
- // r5: string
// r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi)
Label seq_string;
__ and_(r4, r1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag < kConsStringTag);
STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+ STATIC_ASSERT(kConsStringTag < kSlicedStringTag);
__ cmp(r4, Operand(kConsStringTag));
- __ b(gt, &runtime); // External strings go to runtime.
+ __ b(gt, &runtime); // Slices and external strings go to runtime.
__ b(lt, &seq_string); // Sequential strings are handled directly.
// Cons string. Try to recurse (once) on the first substring.
// (This adds a little more generality than necessary to handle flattened
// cons strings, but not much).
- __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset));
- __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
+ __ ldr(r0, FieldMemOperand(r0, ConsString::kFirstOffset));
+ __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset));
__ tst(r1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag == 0);
- __ b(ne, &runtime); // Cons and External strings go to runtime.
+ __ b(ne, &runtime); // Cons, slices and external strings go to runtime.
// Definitly a sequential string.
__ bind(&seq_string);
- // r1: instance type.
- // r2: length
- // r3: from index (untaged smi)
- // r5: string
+ // r0: original string
+ // r1: instance type
+ // r2: result string length
+ // r3: from index (untagged smi)
// r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi)
- __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset));
+ __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
__ cmp(r4, Operand(to));
__ b(lt, &runtime); // Fail if to > length.
to = no_reg;
- // r1: instance type.
- // r2: result string length.
- // r3: from index (untaged smi)
- // r5: string.
+ // r0: original string or left hand side of the original cons string.
+ // r1: instance type
+ // r2: result string length
+ // r3: from index (untagged smi)
// r7 (a.k.a. from): from offset (smi)
// Check for flat ASCII string.
Label non_ascii_flat;
@@ -5561,82 +5587,146 @@
// Sub string of length 2 requested.
// Get the two characters forming the sub string.
- __ add(r5, r5, Operand(r3));
- __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize));
- __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1));
+ __ add(r0, r0, Operand(r3));
+ __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
+ __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1));
// Try to lookup two character string in symbol table.
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_r0);
// r2: result string length.
// r3: two characters combined into halfword in little endian byte order.
__ bind(&make_two_character_string);
__ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime);
__ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
- __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_r0);
__ bind(&result_longer_than_two);
+ // Locate 'from' character of string.
+ __ add(r5, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ __ add(r5, r5, Operand(from, ASR, 1));
+
// Allocate the result.
__ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime);
- // r0: result string.
- // r2: result string length.
- // r5: string.
+ // r0: result string
+ // r2: result string length
+ // r5: first character of substring to copy
// r7 (a.k.a. from): from offset (smi)
// Locate first character of result.
__ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- __ add(r5, r5, Operand(from, ASR, 1));
- // r0: result string.
- // r1: first character of result string.
- // r2: result string length.
- // r5: first character of sub string to copy.
+ // r0: result string
+ // r1: first character of result string
+ // r2: result string length
+ // r5: first character of substring to copy
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
COPY_ASCII | DEST_ALWAYS_ALIGNED);
- __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
- __ add(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_r0);
__ bind(&non_ascii_flat);
- // r2: result string length.
- // r5: string.
+ // r0: original string
+ // r2: result string length
// r7 (a.k.a. from): from offset (smi)
// Check for flat two byte string.
+ // Locate 'from' character of string.
+ __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+ // As "from" is a smi it is 2 times the value which matches the size of a two
+ // byte character.
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ __ add(r5, r5, Operand(from));
+
// Allocate the result.
__ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime);
- // r0: result string.
- // r2: result string length.
- // r5: string.
+ // r0: result string
+ // r2: result string length
+ // r5: first character of substring to copy
// Locate first character of result.
__ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // As "from" is a smi it is 2 times the value which matches the size of a two
- // byte character.
- __ add(r5, r5, Operand(from));
+
from = no_reg;
// r0: result string.
// r1: first character of result.
// r2: result length.
- // r5: first character of string to copy.
+ // r5: first character of substring to copy.
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED);
+ __ jmp(&return_r0);
+
+ if (FLAG_string_slices) {
+ __ bind(&create_slice);
+ // r0: original string
+ // r1: instance type
+ // r2: length
+ // r3: from index (untagged smi)
+ // r6 (a.k.a. to): to (smi)
+ // r7 (a.k.a. from): from offset (smi)
+ Label allocate_slice, sliced_string, seq_string;
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ tst(r1, Operand(kStringRepresentationMask));
+ __ b(eq, &seq_string);
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+ STATIC_ASSERT(kIsIndirectStringMask != 0);
+ __ tst(r1, Operand(kIsIndirectStringMask));
+ // External string. Jump to runtime.
+ __ b(eq, &runtime);
+
+ __ tst(r1, Operand(kSlicedNotConsMask));
+ __ b(ne, &sliced_string);
+ // Cons string. Check whether it is flat, then fetch first part.
+ __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
+ __ LoadRoot(r9, Heap::kEmptyStringRootIndex);
+ __ cmp(r5, r9);
+ __ b(ne, &runtime);
+ __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&sliced_string);
+ // Sliced string. Fetch parent and correct start index by offset.
+ __ ldr(r5, FieldMemOperand(r0, SlicedString::kOffsetOffset));
+ __ add(r7, r7, r5);
+ __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&seq_string);
+ // Sequential string. Just move string to the right register.
+ __ mov(r5, r0);
+
+ __ bind(&allocate_slice);
+ // r1: instance type of original string
+ // r2: length
+ // r5: underlying subject string
+ // r7 (a.k.a. from): from offset (smi)
+ // Allocate new sliced string. At this point we do not reload the instance
+ // type including the string encoding because we simply rely on the info
+ // provided by the original string. It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of
+ // the newly created string's parent anyways due to externalized strings.
+ Label two_byte_slice, set_slice_header;
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ tst(r1, Operand(kStringEncodingMask));
+ __ b(eq, &two_byte_slice);
+ __ AllocateAsciiSlicedString(r0, r2, r3, r4, &runtime);
+ __ jmp(&set_slice_header);
+ __ bind(&two_byte_slice);
+ __ AllocateTwoByteSlicedString(r0, r2, r3, r4, &runtime);
+ __ bind(&set_slice_header);
+ __ str(r7, FieldMemOperand(r0, SlicedString::kOffsetOffset));
+ __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
+ }
+
+ __ bind(&return_r0);
__ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 1604883..50ed8b1 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -193,14 +193,14 @@
// Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context.
- __ mov(r1, Operand(Context::SlotOffset(slot->index())));
+ __ mov(r1, Operand(Context::SlotOffset(var->index())));
__ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid
@@ -244,7 +244,7 @@
ArgumentsAccessStub stub(type);
__ CallStub(&stub);
- Move(arguments->AsSlot(), r0, r1, r2);
+ SetVar(arguments, r0, r1, r2);
}
if (FLAG_trace) {
@@ -258,17 +258,19 @@
scope()->VisitIllegalRedeclaration(this);
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
__ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip));
@@ -367,24 +369,28 @@
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
__ push(result_register());
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
// For simplicity we always test the accumulator register.
- codegen()->Move(result_register(), slot);
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -616,45 +622,54 @@
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return MemOperand(fp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
}
- UNREACHABLE();
- return MemOperand(r0, 0);
+ return MemOperand(fp, offset);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
+ }
+}
+
+
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
// Use destination as scratch.
- MemOperand slot_operand = EmitSlotSearch(source, destination);
- __ ldr(destination, slot_operand);
+ MemOperand location = VarOperand(var, dest);
+ __ ldr(dest, location);
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
__ str(src, location);
// Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- __ RecordWrite(scratch1,
- Operand(Context::SlotOffset(dst->index())),
- scratch2,
+ if (var->IsContextSlot()) {
+ __ RecordWrite(scratch0,
+ Operand(Context::SlotOffset(var->index())),
+ scratch1,
src);
}
}
@@ -687,29 +702,33 @@
}
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
+ __ str(result_register(), StackOperand(variable));
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ str(ip, MemOperand(fp, SlotOffset(slot)));
+ __ str(ip, StackOperand(variable));
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -722,22 +741,27 @@
__ Check(ne, "Declaration in catch context.");
}
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ str(result_register(), ContextOperand(cp, slot->index()));
- int offset = Context::SlotOffset(slot->index());
+ __ str(result_register(), ContextOperand(cp, variable->index()));
+ int offset = Context::SlotOffset(variable->index());
// We know that we have written a function, which is not a smi.
__ mov(r1, Operand(cp));
__ RecordWrite(r1, Operand(offset), r2, result_register());
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ str(ip, ContextOperand(cp, slot->index()));
+ __ str(ip, ContextOperand(cp, variable->index()));
// No write barrier since the_hole_value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ mov(r2, Operand(variable->name()));
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -755,7 +779,7 @@
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
__ Push(cp, r2, r1, r0);
} else {
- __ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
+ __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value.
__ Push(cp, r2, r1, r0);
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
@@ -765,19 +789,16 @@
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
// The context is the first argument.
- __ mov(r2, Operand(pairs));
- __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
- __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, r2, r1, r0);
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ mov(r1, Operand(pairs));
+ __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
+ __ Push(cp, r1, r0);
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1085,10 +1106,9 @@
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register current = cp;
Register next = r1;
Register temp = r2;
@@ -1135,7 +1155,7 @@
}
__ ldr(r0, GlobalObjectOperand());
- __ mov(r2, Operand(slot->var()->name()));
+ __ mov(r2, Operand(var->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
@@ -1144,15 +1164,14 @@
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = cp;
Register next = r3;
Register temp = r4;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1173,59 +1192,30 @@
// This function is used only for loads, not stores, so it's safe to
// return an cp-based operand (the write barrier cannot be allowed to
// destroy the cp register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
- }
- __ jmp(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ ldr(r1,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ mov(r0, Operand(key_literal->handle()));
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ jmp(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
+ __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
}
+ __ jmp(done);
}
}
@@ -1235,66 +1225,60 @@
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
-
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in r2 and the global
- // object (receiver) in r0.
- __ ldr(r0, GlobalObjectOperand());
- __ mov(r2, Operand(var->name()));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(r0);
-
- } else if (slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ mov(r1, Operand(var->name()));
- __ Push(cp, r1); // Context and name.
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
-
- context()->Plug(r0);
-
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- MemOperand slot_operand = EmitSlotSearch(slot, r0);
- __ ldr(r0, slot_operand);
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in r2 and the global
+ // object (receiver) in r0.
+ __ ldr(r0, GlobalObjectOperand());
+ __ mov(r2, Operand(var->name()));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(r0);
- } else if (var->mode() == Variable::LET) {
- // Let bindings may be the hole value if they have not been initialized.
- // Throw a type error in this case.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, r0);
- __ ldr(r0, slot_operand);
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ b(ne, &done);
- __ mov(r0, Operand(var->name()));
- __ push(r0);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot()
+ ? "Context variable"
+ : "Stack variable");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ GetVar(r0, var);
+ __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
+ if (var->mode() == Variable::LET) {
+ Label done;
+ __ b(ne, &done);
+ __ mov(r0, Operand(var->name()));
+ __ push(r0);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&done);
+ } else {
+ __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
+ }
+ context()->Plug(r0);
+ }
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup variable");
+ __ mov(r1, Operand(var->name()));
+ __ Push(cp, r1); // Context and name.
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
context()->Plug(r0);
- } else {
- context()->Plug(slot);
}
}
}
@@ -1828,14 +1812,8 @@
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in r0, variable name in
- // r2, and the global object in r1.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ mov(r2, Operand(var->name()));
__ ldr(r1, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode()
@@ -1844,120 +1822,83 @@
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- // Detect const reinitialization by checking for the hole value.
- __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r1, ip);
- __ b(ne, &skip);
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(r0);
- __ mov(r0, Operand(slot->var()->name()));
- __ Push(cp, r0); // Context and name.
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ ldr(r1, StackOperand(var));
+ __ CompareRoot(r1, Heap::kTheHoleValueRootIndex);
+ __ b(ne, &skip);
+ __ str(result_register(), StackOperand(var));
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(r0);
+ __ mov(r0, Operand(var->name()));
+ __ Push(cp, r0); // Context and name.
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL: {
- Label assign;
- // Check for an initialized let binding.
- __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r1, ip);
- __ b(ne, &assign);
- __ mov(r1, Operand(var->name()));
- __ push(r1);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
- }
- case Slot::CONTEXT: {
- // Let variables may be the hole value if they have not been
- // initialized. Throw a type error in this case.
- Label assign;
- MemOperand target = EmitSlotSearch(slot, r1);
- // Check for an initialized let binding.
- __ ldr(r3, target);
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r3, ip);
- __ b(ne, &assign);
- __ mov(r3, Operand(var->name()));
- __ push(r3);
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ str(result_register(), target);
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(r0); // Value.
+ __ mov(r1, Operand(var->name()));
+ __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, r1, r0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, r1);
+ __ ldr(r3, location);
+ __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
+ __ b(ne, &assign);
+ __ mov(r3, Operand(var->name()));
+ __ push(r3);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ // Perform the assignment.
+ __ bind(&assign);
+ __ str(result_register(), location);
+ if (var->IsContextSlot()) {
// RecordWrite may destroy all its register arguments.
__ mov(r3, result_register());
- int offset = Context::SlotOffset(slot->index());
+ int offset = Context::SlotOffset(var->index());
__ RecordWrite(r1, Operand(offset), r2, r3);
- break;
}
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(r0); // Value.
- __ mov(r1, Operand(slot->var()->name()));
- __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, r1, r0); // Context, name, strict mode.
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
}
} else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
-
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, r1);
- // Perform the assignment and issue the write barrier.
- __ str(result_register(), target);
- // RecordWrite may destroy all its register arguments.
- __ mov(r3, result_register());
- int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
- __ RecordWrite(r1, Operand(offset), r2, r3);
- break;
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, r1);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ ldr(r2, location);
+ __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
+ __ Check(eq, "Let binding re-initialization.");
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(r0); // Value.
- __ mov(r1, Operand(slot->var()->name()));
- __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, r1, r0); // Context, name, strict mode.
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ // Perform the assignment.
+ __ str(r0, location);
+ if (var->IsContextSlot()) {
+ __ mov(r3, r0);
+ __ RecordWrite(r1, Operand(Context::SlotOffset(var->index())), r2, r3);
+ }
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(r0); // Value.
+ __ mov(r1, Operand(var->name()));
+ __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, r1, r0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -2087,9 +2028,8 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2120,9 +2060,8 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
__ Call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2143,8 +2082,7 @@
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2167,8 +2105,13 @@
int receiver_offset = 2 + info_->scope()->num_parameters();
__ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(r1);
- // Push the strict mode flag.
- __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ mov(r1, Operand(Smi::FromInt(strict_mode)));
__ push(r1);
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
@@ -2185,10 +2128,11 @@
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
@@ -2197,7 +2141,7 @@
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot.
@@ -2211,11 +2155,10 @@
// in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(r0);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2223,14 +2166,12 @@
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
+ // Push a copy of the function (found below the arguments) and
// resolve eval.
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(r1);
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in r0 (function) and
// r1 (receiver). Touch up the stack with the right values.
@@ -2240,37 +2181,32 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, r0);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
__ ldr(r0, GlobalObjectOperand());
__ push(r0);
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in r0)
// and the object holding it (returned in edx).
__ push(context_register());
- __ mov(r2, Operand(var->name()));
+ __ mov(r2, Operand(proxy->name()));
__ push(r2);
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ Push(r0, r1); // Function, receiver.
@@ -2295,26 +2231,21 @@
// by LoadContextSlot. That object could be the hole if the
// receiver is implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
+ } else if (property != NULL) {
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
} else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ EmitKeyedCallWithIC(expr, property->key());
}
} else {
+ // Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ ldr(r1, GlobalObjectOperand());
@@ -2579,7 +2510,7 @@
&if_true, &if_false, &fall_through);
__ JumpIfSmi(r0, if_false);
- __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
+ __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
Split(eq, if_true, if_false, fall_through);
@@ -3618,9 +3549,7 @@
__ mov(r2, Operand(expr->name()));
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count,
- NOT_IN_LOOP,
- mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3636,32 +3565,32 @@
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
__ push(r1);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(r0);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ ldr(r2, GlobalObjectOperand());
__ mov(r1, Operand(var->name()));
__ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
__ Push(r2, r1, r0);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(r0);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
// Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects.
- context()->Plug(false);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3936,7 +3865,7 @@
ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(proxy->name()));
@@ -3946,15 +3875,12 @@
__ Call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(r0);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ mov(r0, Operand(proxy->name()));
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 6bad5ac..2e49cae 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -146,7 +146,7 @@
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
- __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ __ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ b(ne, miss);
// Get the value at the masked, scaled index and return.
@@ -194,9 +194,9 @@
const int kElementsStartOffset = StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ tst(scratch1, Operand(kTypeAndReadOnlyMask));
__ b(ne, miss);
@@ -393,7 +393,6 @@
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -734,9 +733,8 @@
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, r0, r2, r3, r4, r5);
@@ -1380,10 +1378,8 @@
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, r1, r2, r3, r4, r5);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 6292ff8..30ccd05 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -311,13 +311,13 @@
void LCallNamed::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallGlobal::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
@@ -546,7 +546,8 @@
void LChunkBuilder::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LChunk building in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -710,9 +711,7 @@
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
- int argument_index_accumulator = 0;
- instr->set_environment(CreateEnvironment(hydrogen_env,
- &argument_index_accumulator));
+ instr->set_environment(CreateEnvironment(hydrogen_env));
return instr;
}
@@ -995,13 +994,10 @@
}
-LEnvironment* LChunkBuilder::CreateEnvironment(
- HEnvironment* hydrogen_env,
- int* argument_index_accumulator) {
+LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (hydrogen_env == NULL) return NULL;
- LEnvironment* outer =
- CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
+ LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
@@ -1011,6 +1007,7 @@
argument_count_,
value_count,
outer);
+ int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@@ -1019,7 +1016,7 @@
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
- op = new LArgument((*argument_index_accumulator)++);
+ op = new LArgument(argument_index++);
} else {
op = UseAny(value);
}
@@ -1864,15 +1861,15 @@
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Representation representation(instr->representation());
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
@@ -1881,7 +1878,7 @@
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
- return (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
+ return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
AssignEnvironment(load_instr) : load_instr;
}
@@ -1932,21 +1929,21 @@
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
bool val_is_temp_register =
- elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS;
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT_ELEMENTS;
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->value());
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index e14e6fc..8c18760 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -1158,7 +1158,7 @@
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -1662,7 +1662,7 @@
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -2159,8 +2159,7 @@
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
- LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
- int* argument_index_accumulator);
+ LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
void VisitInstruction(HInstruction* current);
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 976576b..f5d7449 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -101,7 +101,8 @@
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LCodeGen in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -198,14 +199,14 @@
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context.
- __ mov(r1, Operand(Context::SlotOffset(slot->index())));
+ __ mov(r1, Operand(Context::SlotOffset(var->index())));
__ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid
@@ -2410,11 +2411,11 @@
__ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
__ ubfx(scratch, scratch, Map::kElementsKindShift,
Map::kElementsKindBitCount);
- __ cmp(scratch, Operand(JSObject::FAST_ELEMENTS));
+ __ cmp(scratch, Operand(FAST_ELEMENTS));
__ b(eq, &done);
- __ cmp(scratch, Operand(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmp(scratch, Operand(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ b(lt, &fail);
- __ cmp(scratch, Operand(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmp(scratch, Operand(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ b(le, &done);
__ bind(&fail);
__ Abort("Check for fast or external elements failed.");
@@ -2478,7 +2479,7 @@
Register scratch = scratch0();
int shift_size =
- ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
+ ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
int constant_key = 0;
if (key_is_constant) {
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
@@ -2515,7 +2516,7 @@
LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
Register key = no_reg;
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
bool key_is_constant = instr->key()->IsConstantOperand();
int constant_key = 0;
if (key_is_constant) {
@@ -2528,18 +2529,18 @@
}
int shift_size = ElementsKindToShiftSize(elements_kind);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister result = ToDoubleRegister(instr->result());
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size))
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vldr(result.low(), scratch0(), 0);
__ vcvt_f64_f32(result, result.low());
- } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ vldr(result, scratch0(), 0);
}
} else {
@@ -2548,23 +2549,23 @@
? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size));
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ ldrsb(result, mem_operand);
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ ldrb(result, mem_operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ ldrsh(result, mem_operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ ldrh(result, mem_operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ ldr(result, mem_operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ ldr(result, mem_operand);
__ cmp(result, Operand(0x80000000));
// TODO(danno): we could be more clever here, perhaps having a special
@@ -2572,12 +2573,12 @@
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(cs, instr->environment());
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3177,7 +3178,7 @@
int arity = instr->arity();
Handle<Code> ic =
- isolate()->stub_cache()->ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -3189,7 +3190,7 @@
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(r2, Operand(instr->name()));
CallCode(ic, mode, instr);
// Restore context register.
@@ -3201,7 +3202,7 @@
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
- CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ Drop(1);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3214,7 +3215,7 @@
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(r2, Operand(instr->name()));
CallCode(ic, mode, instr);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3340,7 +3341,7 @@
} else {
key = ToRegister(instr->key());
}
- int shift_size = ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
+ int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
@@ -3367,7 +3368,7 @@
Register external_pointer = ToRegister(instr->external_pointer());
Register key = no_reg;
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
bool key_is_constant = instr->key()->IsConstantOperand();
int constant_key = 0;
if (key_is_constant) {
@@ -3380,17 +3381,17 @@
}
int shift_size = ElementsKindToShiftSize(elements_kind);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
DwVfpRegister value(ToDoubleRegister(instr->value()));
Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
: Operand(key, LSL, shift_size));
__ add(scratch0(), external_pointer, operand);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ vcvt_f32_f64(double_scratch0().low(), value);
__ vstr(double_scratch0().low(), scratch0(), 0);
- } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
+ } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
__ vstr(value, scratch0(), 0);
}
} else {
@@ -3399,25 +3400,25 @@
? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size));
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(value, mem_operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(value, mem_operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(value, mem_operand);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3509,7 +3510,8 @@
// Dispatch on the encoding: ASCII or two-byte.
Label ascii_string;
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ tst(result, Operand(kStringEncodingMask));
__ b(ne, &ascii_string);
diff --git a/src/arm/lithium-gap-resolver-arm.h b/src/arm/lithium-gap-resolver-arm.h
index 334d292..9dd09c8 100644
--- a/src/arm/lithium-gap-resolver-arm.h
+++ b/src/arm/lithium-gap-resolver-arm.h
@@ -40,7 +40,6 @@
class LGapResolver BASE_EMBEDDED {
public:
-
explicit LGapResolver(LCodeGen* owner);
// Resolve a set of parallel moves, emitting assembler instructions.
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 88477bb..f37f310 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -760,9 +760,9 @@
str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
- mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
str(fp, MemOperand(ip));
- mov(ip, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
str(cp, MemOperand(ip));
// Optionally save all double registers.
@@ -838,11 +838,11 @@
// Clear top frame.
mov(r3, Operand(0, RelocInfo::NONE));
- mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
str(r3, MemOperand(ip));
// Restore current context from top and clear it in debug mode.
- mov(ip, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
ldr(cp, MemOperand(ip));
#ifdef DEBUG
str(r3, MemOperand(ip));
@@ -1118,7 +1118,7 @@
}
stm(db_w, sp, r3.bit() | cp.bit() | fp.bit() | lr.bit());
// Save the current handler as the next handler.
- mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(r1, MemOperand(r3));
push(r1);
// Link this handler as the new current one.
@@ -1134,7 +1134,7 @@
mov(r7, Operand(0, RelocInfo::NONE)); // NULL frame pointer.
stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | lr.bit());
// Save the current handler as the next handler.
- mov(r7, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r7, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(r6, MemOperand(r7));
push(r6);
// Link this handler as the new current one.
@@ -1146,7 +1146,7 @@
void MacroAssembler::PopTryHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(r1);
- mov(ip, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
str(r1, MemOperand(ip));
}
@@ -1166,7 +1166,7 @@
}
// Drop the sp to the top of the handler.
- mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(sp, MemOperand(r3));
// Restore the next handler.
@@ -1206,7 +1206,7 @@
}
// Drop sp to the top stack handler.
- mov(r3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ mov(r3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ldr(sp, MemOperand(r3));
// Unwind the handlers until the ENTRY handler is found.
@@ -1230,7 +1230,7 @@
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address, isolate());
+ Isolate::kExternalCaughtExceptionAddress, isolate());
mov(r0, Operand(false, RelocInfo::NONE));
mov(r2, Operand(external_caught));
str(r0, MemOperand(r2));
@@ -1238,7 +1238,7 @@
// Set pending exception and r0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate())));
str(r0, MemOperand(r2));
}
@@ -1421,7 +1421,7 @@
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ldr(t1, FieldMemOperand(t2, kDetailsOffset));
- tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
+ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
b(ne, miss);
// Get the value at the masked, scaled index and return.
@@ -1725,6 +1725,46 @@
}
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+void MacroAssembler::AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedAsciiStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
void MacroAssembler::CompareObjectType(Register object,
Register map,
Register type_reg,
@@ -1753,7 +1793,7 @@
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
cmp(scratch, Operand(Map::kMaximumBitField2FastElementValue));
b(hi, fail);
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 9c653ad..6084fde 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -532,6 +532,16 @@
Register scratch1,
Register scratch2,
Label* gc_required);
+ void AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
// Allocates a heap number or jumps to the gc_required label if the young
// space is full and a scavenge is needed. All registers are clobbered also
@@ -586,9 +596,7 @@
// Compare instance type in a map. map contains a valid map object whose
// object type should be compared with the given type. This both
- // sets the flags and leaves the object type in the type_reg register. It
- // leaves the heap object in the heap_object register unless the heap_object
- // register is the same register as type_reg.
+ // sets the flags and leaves the object type in the type_reg register.
void CompareInstanceType(Register map,
Register type_reg,
InstanceType type);
diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h
index 0e65386..5c8ed06 100644
--- a/src/arm/regexp-macro-assembler-arm.h
+++ b/src/arm/regexp-macro-assembler-arm.h
@@ -116,6 +116,7 @@
static int CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame);
+
private:
// Offsets from frame_pointer() of function parameters and stored registers.
static const int kFramePointer = 0;
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 5345892..f856592 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -3099,7 +3099,7 @@
// -- r1 : receiver
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(r1,
@@ -3193,7 +3193,7 @@
// -- r3 : scratch
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
@@ -3438,25 +3438,25 @@
}
-static bool IsElementTypeSigned(JSObject::ElementsKind elements_kind) {
+static bool IsElementTypeSigned(ElementsKind elements_kind) {
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
return true;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
return false;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
return false;
}
@@ -3466,7 +3466,7 @@
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- lr : return address
// -- r0 : key
@@ -3501,24 +3501,24 @@
Register value = r2;
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ ldrsb(value, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ ldrb(value, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ ldrsh(value, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ ldrh(value, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ ldr(value, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ add(r2, r3, Operand(key, LSL, 1));
@@ -3527,7 +3527,7 @@
__ ldr(value, MemOperand(r3, key, LSL, 1));
}
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
__ add(r2, r3, Operand(key, LSL, 2));
@@ -3539,10 +3539,10 @@
__ ldr(r3, MemOperand(r4, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3556,7 +3556,7 @@
// d0: value (if VFP3 is supported)
// r2/r3: value (if VFP3 is not supported)
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
// For the Int and UnsignedInt array types, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
@@ -3600,7 +3600,7 @@
__ str(dst2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
@@ -3665,7 +3665,7 @@
__ mov(r0, r4);
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
if (CpuFeatures::IsSupported(VFP3)) {
@@ -3735,7 +3735,7 @@
__ mov(r0, r3);
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
// Allocate a HeapNumber for the result. Don't use r0 and r1 as
@@ -3792,7 +3792,7 @@
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- r0 : value
// -- r1 : key
@@ -3824,7 +3824,7 @@
// Handle both smis and HeapNumbers in the fast path. Go to the
// runtime for all other kinds of values.
// r3: external array.
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(value, &slow);
} else {
@@ -3836,29 +3836,29 @@
// r3: base pointer of external storage.
// r5: value (integer).
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
// Clamp the value to [0..255].
__ Usat(r5, 8, Operand(r5));
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
__ SmiUntag(r4, key);
StoreIntAsFloat(masm, r3, r4, r5, r6, r7, r9);
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ add(r3, r3, Operand(key, LSL, 2));
// r3: effective address of the double element
FloatingPointHelper::Destination destination;
@@ -3879,10 +3879,10 @@
__ str(r7, MemOperand(r3, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3890,7 +3890,7 @@
// Entry registers are intact, r0 holds the value which is the return value.
__ Ret();
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
// r3: external array.
__ bind(&check_heap_number);
__ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
@@ -3906,7 +3906,7 @@
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
// vldr requires offset to be a multiple of 4 so we can not
// include -kHeapObjectTag into it.
__ sub(r5, r0, Operand(kHeapObjectTag));
@@ -3914,7 +3914,7 @@
__ add(r5, r3, Operand(key, LSL, 1));
__ vcvt_f32_f64(s0, d0);
__ vstr(s0, r5, 0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sub(r5, r0, Operand(kHeapObjectTag));
__ vldr(d0, r5, HeapNumber::kValueOffset);
__ add(r5, r3, Operand(key, LSL, 2));
@@ -3927,25 +3927,25 @@
__ EmitECMATruncate(r5, d0, s2, r6, r7, r9);
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3959,7 +3959,7 @@
__ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
__ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
Label done, nan_or_infinity_or_zero;
static const int kMantissaInHiWordShift =
kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
@@ -4011,7 +4011,7 @@
__ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
__ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
__ b(&done);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ add(r7, r3, Operand(key, LSL, 2));
// r7: effective address of destination element.
__ str(r6, MemOperand(r7, 0));
@@ -4066,25 +4066,25 @@
__ bind(&done);
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ strb(r5, MemOperand(r3, key, LSR, 1));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ strh(r5, MemOperand(r3, key, LSL, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ str(r5, MemOperand(r3, key, LSL, 1));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
diff --git a/src/array.js b/src/array.js
index f73b0c1..98fe3ac 100644
--- a/src/array.js
+++ b/src/array.js
@@ -208,7 +208,7 @@
// Call ToString if toLocaleString is not a function.
// See issue 877615.
var e_obj = ToObject(e);
- if (IS_FUNCTION(e_obj.toLocaleString))
+ if (IS_SPEC_FUNCTION(e_obj.toLocaleString))
return ToString(e_obj.toLocaleString());
else
return ToString(e);
@@ -730,7 +730,7 @@
// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.
- if (!IS_FUNCTION(comparefn)) {
+ if (!IS_SPEC_FUNCTION(comparefn)) {
comparefn = function (x, y) {
if (x === y) return 0;
if (%_IsSmi(x) && %_IsSmi(y)) {
@@ -993,7 +993,7 @@
["Array.prototype.filter"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1022,7 +1022,7 @@
["Array.prototype.forEach"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1048,7 +1048,7 @@
["Array.prototype.some"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1073,7 +1073,7 @@
["Array.prototype.every"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1097,7 +1097,7 @@
["Array.prototype.map"]);
}
- if (!IS_FUNCTION(f)) {
+ if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
if (IS_NULL_OR_UNDEFINED(receiver)) {
@@ -1245,7 +1245,7 @@
["Array.prototype.reduce"]);
}
- if (!IS_FUNCTION(callback)) {
+ if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]);
}
@@ -1281,7 +1281,7 @@
["Array.prototype.reduceRight"]);
}
- if (!IS_FUNCTION(callback)) {
+ if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]);
}
var i = ToUint32(this.length) - 1;
@@ -1314,12 +1314,13 @@
// -------------------------------------------------------------------
-function SetupArray() {
- // Setup non-enumerable constructor property on the Array.prototype
+function SetUpArray() {
+ %CheckIsBootstrapping();
+ // Set up non-enumerable constructor property on the Array.prototype
// object.
%SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
- // Setup non-enumerable functions on the Array object.
+ // Set up non-enumerable functions on the Array object.
InstallFunctions($Array, DONT_ENUM, $Array(
"isArray", ArrayIsArray
));
@@ -1337,7 +1338,7 @@
return f;
}
- // Setup non-enumerable functions of the Array.prototype object and
+ // Set up non-enumerable functions of the Array.prototype object and
// set their names.
// Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla.
@@ -1368,19 +1369,13 @@
%FinishArrayPrototypeSetup($Array.prototype);
// The internal Array prototype doesn't need to be fancy, since it's never
- // exposed to user code, so no hidden prototypes or DONT_ENUM attributes
- // are necessary.
- // The null __proto__ ensures that we never inherit any user created
- // getters or setters from, e.g., Object.prototype.
- InternalArray.prototype.__proto__ = null;
- // Adding only the functions that are actually used, and a toString.
- InternalArray.prototype.join = getFunction("join", ArrayJoin);
- InternalArray.prototype.pop = getFunction("pop", ArrayPop);
- InternalArray.prototype.push = getFunction("push", ArrayPush);
- InternalArray.prototype.toString = function() {
- return "Internal Array, length " + this.length;
- };
+ // exposed to user code.
+ // Adding only the functions that are actually used.
+ SetUpLockedPrototype(InternalArray, $Array(), $Array(
+ "join", getFunction("join", ArrayJoin),
+ "pop", getFunction("pop", ArrayPop),
+ "push", getFunction("push", ArrayPush)
+ ));
}
-
-SetupArray();
+SetUpArray();
diff --git a/src/ast.cc b/src/ast.cc
index 7319abe..418cc43 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -36,20 +36,9 @@
namespace v8 {
namespace internal {
-AstSentinels::AstSentinels()
- : this_proxy_(Isolate::Current(), true),
- identifier_proxy_(Isolate::Current(), false),
- valid_left_hand_side_sentinel_(Isolate::Current()),
- this_property_(Isolate::Current(), &this_proxy_, NULL, 0),
- call_sentinel_(Isolate::Current(), NULL, NULL, 0) {
-}
-
-
// ----------------------------------------------------------------------------
// All the Accept member functions for each syntax tree node type.
-void Slot::Accept(AstVisitor* v) { v->VisitSlot(this); }
-
#define DECL_ACCEPT(type) \
void type::Accept(AstVisitor* v) { v->Visit##type(this); }
AST_NODE_LIST(DECL_ACCEPT)
@@ -101,15 +90,6 @@
}
-VariableProxy::VariableProxy(Isolate* isolate, bool is_this)
- : Expression(isolate),
- var_(NULL),
- is_this_(is_this),
- inside_with_(false),
- is_trivial_(false) {
-}
-
-
void VariableProxy::BindTo(Variable* var) {
ASSERT(var_ == NULL); // must be bound only once
ASSERT(var != NULL); // must bind
@@ -414,12 +394,6 @@
}
-bool Slot::IsInlineable() const {
- UNREACHABLE();
- return false;
-}
-
-
bool ForInStatement::IsInlineable() const {
return false;
}
@@ -430,11 +404,6 @@
}
-bool ExitContextStatement::IsInlineable() const {
- return false;
-}
-
-
bool SwitchStatement::IsInlineable() const {
return false;
}
@@ -487,12 +456,6 @@
}
-bool ValidLeftHandSideSentinel::IsInlineable() const {
- UNREACHABLE();
- return false;
-}
-
-
bool ForStatement::IsInlineable() const {
return (init() == NULL || init()->IsInlineable())
&& (cond() == NULL || cond()->IsInlineable())
@@ -566,7 +529,7 @@
bool VariableProxy::IsInlineable() const {
- return var()->is_global() || var()->IsStackAllocated();
+ return var()->IsUnallocated() || var()->IsStackAllocated();
}
@@ -1006,7 +969,7 @@
public:
RegExpUnparser();
void VisitCharacterRange(CharacterRange that);
- SmartPointer<const char> ToString() { return stream_.ToCString(); }
+ SmartArrayPointer<const char> ToString() { return stream_.ToCString(); }
#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
#undef MAKE_CASE
@@ -1161,7 +1124,7 @@
}
-SmartPointer<const char> RegExpTree::ToString() {
+SmartArrayPointer<const char> RegExpTree::ToString() {
RegExpUnparser unparser;
Accept(&unparser, NULL);
return unparser.ToString();
diff --git a/src/ast.h b/src/ast.h
index 74182d5..b56205f 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -62,7 +62,6 @@
V(BreakStatement) \
V(ReturnStatement) \
V(WithStatement) \
- V(ExitContextStatement) \
V(SwitchStatement) \
V(DoWhileStatement) \
V(WhileStatement) \
@@ -134,6 +133,10 @@
static const int kNoNumber = -1;
static const int kFunctionEntryId = 2; // Using 0 could disguise errors.
+ // This AST id identifies the point after the declarations have been
+ // visited. We need it to capture the environment effects of declarations
+ // that emit code (function declarations).
+ static const int kDeclarationsId = 3;
// Override ZoneObject's new to count allocated AST nodes.
void* operator new(size_t size, Zone* zone) {
@@ -161,7 +164,6 @@
virtual BreakableStatement* AsBreakableStatement() { return NULL; }
virtual IterationStatement* AsIterationStatement() { return NULL; }
virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
- virtual Slot* AsSlot() { return NULL; }
// True if the node is simple enough for us to inline calls containing it.
virtual bool IsInlineable() const = 0;
@@ -316,20 +318,6 @@
};
-/**
- * A sentinel used during pre parsing that represents some expression
- * that is a valid left hand side without having to actually build
- * the expression.
- */
-class ValidLeftHandSideSentinel: public Expression {
- public:
- explicit ValidLeftHandSideSentinel(Isolate* isolate) : Expression(isolate) {}
- virtual bool IsValidLeftHandSide() { return true; }
- virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
- virtual bool IsInlineable() const;
-};
-
-
class BreakableStatement: public Statement {
public:
enum Type {
@@ -404,10 +392,14 @@
class Declaration: public AstNode {
public:
- Declaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* fun)
+ Declaration(VariableProxy* proxy,
+ Variable::Mode mode,
+ FunctionLiteral* fun,
+ Scope* scope)
: proxy_(proxy),
mode_(mode),
- fun_(fun) {
+ fun_(fun),
+ scope_(scope) {
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -421,11 +413,15 @@
Variable::Mode mode() const { return mode_; }
FunctionLiteral* fun() const { return fun_; } // may be NULL
virtual bool IsInlineable() const;
+ Scope* scope() const { return scope_; }
private:
VariableProxy* proxy_;
Variable::Mode mode_;
FunctionLiteral* fun_;
+
+ // Nested scope from which the declaration originated.
+ Scope* scope_;
};
@@ -684,14 +680,6 @@
};
-class ExitContextStatement: public Statement {
- public:
- virtual bool IsInlineable() const;
-
- DECLARE_NODE_TYPE(ExitContextStatement)
-};
-
-
class CaseClause: public ZoneObject {
public:
CaseClause(Isolate* isolate,
@@ -1114,9 +1102,6 @@
DECLARE_NODE_TYPE(VariableProxy)
- // Type testing & conversion
- Variable* AsVariable() { return (this == NULL) ? NULL : var_; }
-
virtual bool IsValidLeftHandSide() {
return var_ == NULL ? true : var_->IsValidLeftHandSide();
}
@@ -1133,10 +1118,7 @@
return !is_this() && name().is_identical_to(n);
}
- bool IsArguments() {
- Variable* variable = AsVariable();
- return (variable == NULL) ? false : variable->is_arguments();
- }
+ bool IsArguments() { return var_ != NULL && var_->is_arguments(); }
Handle<String> name() const { return name_; }
Variable* var() const { return var_; }
@@ -1162,73 +1144,11 @@
bool is_this,
bool inside_with,
int position = RelocInfo::kNoPosition);
- VariableProxy(Isolate* isolate, bool is_this);
friend class Scope;
};
-class VariableProxySentinel: public VariableProxy {
- public:
- virtual bool IsValidLeftHandSide() { return !is_this(); }
-
- private:
- VariableProxySentinel(Isolate* isolate, bool is_this)
- : VariableProxy(isolate, is_this) { }
-
- friend class AstSentinels;
-};
-
-
-class Slot: public Expression {
- public:
- enum Type {
- // A slot in the parameter section on the stack. index() is
- // the parameter index, counting left-to-right, starting at 0.
- PARAMETER,
-
- // A slot in the local section on the stack. index() is
- // the variable index in the stack frame, starting at 0.
- LOCAL,
-
- // An indexed slot in a heap context. index() is the
- // variable index in the context object on the heap,
- // starting at 0. var()->scope() is the corresponding
- // scope.
- CONTEXT,
-
- // A named slot in a heap context. var()->name() is the
- // variable name in the context object on the heap,
- // with lookup starting at the current context. index()
- // is invalid.
- LOOKUP
- };
-
- Slot(Isolate* isolate, Variable* var, Type type, int index)
- : Expression(isolate), var_(var), type_(type), index_(index) {
- ASSERT(var != NULL);
- }
-
- virtual void Accept(AstVisitor* v);
-
- virtual Slot* AsSlot() { return this; }
-
- bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; }
-
- // Accessors
- Variable* var() const { return var_; }
- Type type() const { return type_; }
- int index() const { return index_; }
- bool is_arguments() const { return var_->is_arguments(); }
- virtual bool IsInlineable() const;
-
- private:
- Variable* var_;
- Type type_;
- int index_;
-};
-
-
class Property: public Expression {
public:
Property(Isolate* isolate,
@@ -1337,36 +1257,6 @@
};
-class AstSentinels {
- public:
- ~AstSentinels() { }
-
- // Returns a property singleton property access on 'this'. Used
- // during preparsing.
- Property* this_property() { return &this_property_; }
- VariableProxySentinel* this_proxy() { return &this_proxy_; }
- VariableProxySentinel* identifier_proxy() { return &identifier_proxy_; }
- ValidLeftHandSideSentinel* valid_left_hand_side_sentinel() {
- return &valid_left_hand_side_sentinel_;
- }
- Call* call_sentinel() { return &call_sentinel_; }
- EmptyStatement* empty_statement() { return &empty_statement_; }
-
- private:
- AstSentinels();
- VariableProxySentinel this_proxy_;
- VariableProxySentinel identifier_proxy_;
- ValidLeftHandSideSentinel valid_left_hand_side_sentinel_;
- Property this_property_;
- Call call_sentinel_;
- EmptyStatement empty_statement_;
-
- friend class Isolate;
-
- DISALLOW_COPY_AND_ASSIGN(AstSentinels);
-};
-
-
class CallNew: public Expression {
public:
CallNew(Isolate* isolate,
@@ -1885,7 +1775,7 @@
// expression.
virtual Interval CaptureRegisters() { return Interval::Empty(); }
virtual void AppendToText(RegExpText* text);
- SmartPointer<const char> ToString();
+ SmartArrayPointer<const char> ToString();
#define MAKE_ASTYPE(Name) \
virtual RegExp##Name* As##Name(); \
virtual bool Is##Name();
@@ -2239,9 +2129,6 @@
void SetStackOverflow() { stack_overflow_ = true; }
void ClearStackOverflow() { stack_overflow_ = false; }
- // Nodes not appearing in the AST, including slots.
- virtual void VisitSlot(Slot* node) { UNREACHABLE(); }
-
// Individual AST nodes.
#define DEF_VISIT(type) \
virtual void Visit##type(type* node) = 0;
diff --git a/src/bignum-dtoa.cc b/src/bignum-dtoa.cc
index 088dd79..a961690 100644
--- a/src/bignum-dtoa.cc
+++ b/src/bignum-dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -27,7 +27,10 @@
#include <math.h>
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
+
#include "bignum-dtoa.h"
#include "bignum.h"
diff --git a/src/bignum.h b/src/bignum.h
index 1d2bff6..dcc4fa7 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -92,6 +92,7 @@
static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) < 0;
}
+
private:
typedef uint32_t Chunk;
typedef uint64_t DoubleChunk;
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 9f01664..f07e625 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -350,7 +350,14 @@
prototype,
call_code,
is_ecma_native);
- SetLocalPropertyNoThrow(target, symbol, function, DONT_ENUM);
+ PropertyAttributes attributes;
+ if (target->IsJSBuiltinsObject()) {
+ attributes =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+ } else {
+ attributes = DONT_ENUM;
+ }
+ SetLocalPropertyNoThrow(target, symbol, function, attributes);
if (is_ecma_native) {
function->shared()->set_instance_class_name(*symbol);
}
@@ -1060,7 +1067,7 @@
Handle<Map> new_map = factory->CopyMapDropTransitions(old_map);
new_map->set_pre_allocated_property_fields(2);
Handle<JSObject> result = factory->NewJSObjectFromMap(new_map);
- new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+ new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
// Set up a well-formed parameter map to make assertions happy.
Handle<FixedArray> elements = factory->NewFixedArray(2);
elements->set_map(heap->non_strict_arguments_elements_map());
@@ -1677,7 +1684,6 @@
global_context()->set_regexp_result_map(*initial_map);
}
-
#ifdef DEBUG
builtins->Verify();
#endif
@@ -2056,7 +2062,7 @@
break;
}
case MAP_TRANSITION:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
// Ignore non-properties.
diff --git a/src/builtins.cc b/src/builtins.cc
index d403a95..e6a0699 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1583,7 +1583,6 @@
functions->s_name = #aname; \
functions->name = k##aname; \
functions->flags = Code::ComputeFlags(Code::kind, \
- NOT_IN_LOOP, \
state, \
extra); \
functions->extra_args = NO_EXTRA_ARGUMENTS; \
diff --git a/src/builtins.h b/src/builtins.h
index f9a5a13..31090d3 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -238,6 +238,8 @@
V(FILTER_KEY, 1) \
V(CALL_NON_FUNCTION, 0) \
V(CALL_NON_FUNCTION_AS_CONSTRUCTOR, 0) \
+ V(CALL_FUNCTION_PROXY, 1) \
+ V(CALL_FUNCTION_PROXY_AS_CONSTRUCTOR, 1) \
V(TO_OBJECT, 0) \
V(TO_NUMBER, 0) \
V(TO_STRING, 0) \
diff --git a/src/cached-powers.h b/src/cached-powers.h
index 2ae5619..88df222 100644
--- a/src/cached-powers.h
+++ b/src/cached-powers.h
@@ -35,7 +35,6 @@
class PowersOfTenCache {
public:
-
// Not all powers of ten are cached. The decimal exponent of two neighboring
// cached numbers will differ by kDecimalExponentDistance.
static const int kDecimalExponentDistance;
diff --git a/src/circular-queue-inl.h b/src/circular-queue-inl.h
index 349f222..373bf60 100644
--- a/src/circular-queue-inl.h
+++ b/src/circular-queue-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -25,8 +25,8 @@
// (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_CIRCULAR_BUFFER_INL_H_
-#define V8_CIRCULAR_BUFFER_INL_H_
+#ifndef V8_CIRCULAR_QUEUE_INL_H_
+#define V8_CIRCULAR_QUEUE_INL_H_
#include "circular-queue.h"
@@ -50,4 +50,4 @@
} } // namespace v8::internal
-#endif // V8_CIRCULAR_BUFFER_INL_H_
+#endif // V8_CIRCULAR_QUEUE_INL_H_
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 5535d17..00da4cb 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -61,7 +61,7 @@
}
-SmartPointer<const char> CodeStub::GetName() {
+SmartArrayPointer<const char> CodeStub::GetName() {
char buffer[100];
NoAllocationStringAllocator allocator(buffer,
static_cast<unsigned>(sizeof(buffer)));
@@ -75,7 +75,7 @@
code->set_major_key(MajorKey());
Isolate* isolate = masm->isolate();
- SmartPointer<const char> name = GetName();
+ SmartArrayPointer<const char> name = GetName();
PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
Counters* counters = isolate->counters();
@@ -114,7 +114,6 @@
// Copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
static_cast<Code::Kind>(GetCodeKind()),
- InLoop(),
GetICState());
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
@@ -152,7 +151,6 @@
// Try to copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
static_cast<Code::Kind>(GetCodeKind()),
- InLoop(),
GetICState());
Object* new_object;
{ MaybeObject* maybe_new_object =
@@ -246,27 +244,27 @@
void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
- case JSObject::FAST_ELEMENTS:
+ case FAST_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
break;
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadExternalArray(masm, elements_kind_);
break;
- case JSObject::DICTIONARY_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
break;
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -275,28 +273,28 @@
void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind_) {
- case JSObject::FAST_ELEMENTS:
+ case FAST_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
break;
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
is_js_array_);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
break;
- case JSObject::DICTIONARY_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
break;
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -316,17 +314,12 @@
void CallFunctionStub::PrintName(StringStream* stream) {
- const char* in_loop_name = NULL; // Make g++ happy.
- switch (in_loop_) {
- case NOT_IN_LOOP: in_loop_name = ""; break;
- case IN_LOOP: in_loop_name = "_InLoop"; break;
- }
const char* flags_name = NULL; // Make g++ happy.
switch (flags_) {
case NO_CALL_FUNCTION_FLAGS: flags_name = ""; break;
case RECEIVER_MIGHT_BE_IMPLICIT: flags_name = "_Implicit"; break;
}
- stream->Add("CallFunctionStub_Args%d%s%s", argc_, in_loop_name, flags_name);
+ stream->Add("CallFunctionStub_Args%d%s", argc_, flags_name);
}
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 89e99a8..64c89b9 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -168,10 +168,6 @@
virtual Major MajorKey() = 0;
virtual int MinorKey() = 0;
- // The CallFunctionStub needs to override this so it can encode whether a
- // lazily generated function should be fully optimized or not.
- virtual InLoopFlag InLoop() { return NOT_IN_LOOP; }
-
// BinaryOpStub needs to override this.
virtual int GetCodeKind();
@@ -181,7 +177,7 @@
}
// Returns a name for logging/debugging purposes.
- SmartPointer<const char> GetName();
+ SmartArrayPointer<const char> GetName();
virtual void PrintName(StringStream* stream) {
stream->Add("%s", MajorName(MajorKey(), false));
}
@@ -646,8 +642,8 @@
class CallFunctionStub: public CodeStub {
public:
- CallFunctionStub(int argc, InLoopFlag in_loop, CallFunctionFlags flags)
- : argc_(argc), in_loop_(in_loop), flags_(flags) { }
+ CallFunctionStub(int argc, CallFunctionFlags flags)
+ : argc_(argc), flags_(flags) { }
void Generate(MacroAssembler* masm);
@@ -657,26 +653,20 @@
private:
int argc_;
- InLoopFlag in_loop_;
CallFunctionFlags flags_;
virtual void PrintName(StringStream* stream);
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
- class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
- class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
- class ArgcBits: public BitField<int, 2, 32 - 2> {};
+ class FlagBits: public BitField<CallFunctionFlags, 0, 1> {};
+ class ArgcBits: public BitField<unsigned, 1, 32 - 1> {};
Major MajorKey() { return CallFunction; }
int MinorKey() {
// Encode the parameters in a unique 32 bit value.
- return InLoopBits::encode(in_loop_)
- | FlagBits::encode(flags_)
- | ArgcBits::encode(argc_);
+ return FlagBits::encode(flags_) | ArgcBits::encode(argc_);
}
- InLoopFlag InLoop() { return in_loop_; }
-
bool ReceiverMightBeImplicit() {
return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0;
}
@@ -860,7 +850,7 @@
class KeyedLoadElementStub : public CodeStub {
public:
- explicit KeyedLoadElementStub(JSObject::ElementsKind elements_kind)
+ explicit KeyedLoadElementStub(ElementsKind elements_kind)
: elements_kind_(elements_kind)
{ }
@@ -870,7 +860,7 @@
void Generate(MacroAssembler* masm);
private:
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
DISALLOW_COPY_AND_ASSIGN(KeyedLoadElementStub);
};
@@ -879,20 +869,20 @@
class KeyedStoreElementStub : public CodeStub {
public:
KeyedStoreElementStub(bool is_js_array,
- JSObject::ElementsKind elements_kind)
+ ElementsKind elements_kind)
: is_js_array_(is_js_array),
elements_kind_(elements_kind) { }
Major MajorKey() { return KeyedStoreElement; }
int MinorKey() {
- return (is_js_array_ ? 0 : JSObject::kElementsKindCount) + elements_kind_;
+ return (is_js_array_ ? 0 : kElementsKindCount) + elements_kind_;
}
void Generate(MacroAssembler* masm);
private:
bool is_js_array_;
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
DISALLOW_COPY_AND_ASSIGN(KeyedStoreElementStub);
};
diff --git a/src/compilation-cache.h b/src/compilation-cache.h
index 1fcf753..4339d22 100644
--- a/src/compilation-cache.h
+++ b/src/compilation-cache.h
@@ -242,6 +242,7 @@
// cache during debugging to make sure new scripts are always compiled.
void Enable();
void Disable();
+
private:
explicit CompilationCache(Isolate* isolate);
~CompilationCache();
diff --git a/src/compiler.cc b/src/compiler.cc
index b33c374..5e1c4a9 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -41,6 +41,7 @@
#include "parser.h"
#include "rewriter.h"
#include "runtime-profiler.h"
+#include "scanner-character-streams.h"
#include "scopeinfo.h"
#include "scopes.h"
#include "vm-state-inl.h"
diff --git a/src/compiler.h b/src/compiler.h
index 181446b..69ab27d 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -49,11 +49,11 @@
ASSERT(Isolate::Current() == isolate_);
return isolate_;
}
- bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
- bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
- bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
- bool is_strict_mode() const { return (flags_ & IsStrictMode::mask()) != 0; }
- bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
+ bool is_lazy() const { return IsLazy::decode(flags_); }
+ bool is_eval() const { return IsEval::decode(flags_); }
+ bool is_global() const { return IsGlobal::decode(flags_); }
+ bool is_strict_mode() const { return IsStrictMode::decode(flags_); }
+ bool is_in_loop() const { return IsInLoop::decode(flags_); }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
Handle<Code> code() const { return code_; }
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index 1a20645..41cf0d5 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -32,19 +32,22 @@
#include <math.h>
#include <float.h> // Required for DBL_MAX and on Win32 for finite()
#include <stdarg.h>
+#include "globals.h" // Required for V8_INFINITY
// ----------------------------------------------------------------------------
// Extra POSIX/ANSI functions for Win32/MSVC.
#include "conversions.h"
-#include "strtod.h"
+#include "double.h"
#include "platform.h"
+#include "scanner.h"
+#include "strtod.h"
namespace v8 {
namespace internal {
static inline double JunkStringValue() {
- return BitCast<double, uint64_t>(kQuietNaNMask);
+ return std::numeric_limits<double>::quiet_NaN();
}
@@ -87,12 +90,15 @@
int32_t DoubleToInt32(double x) {
int32_t i = FastD2I(x);
if (FastI2D(i) == x) return i;
- static const double two32 = 4294967296.0;
- static const double two31 = 2147483648.0;
- if (!isfinite(x) || x == 0) return 0;
- if (x < 0 || x >= two32) x = modulo(x, two32);
- x = (x >= 0) ? floor(x) : ceil(x) + two32;
- return (int32_t) ((x >= two31) ? x - two32 : x);
+ Double d(x);
+ int exponent = d.Exponent();
+ if (exponent < 0) {
+ if (exponent <= -Double::kSignificandSize) return 0;
+ return d.Sign() * static_cast<int32_t>(d.Significand() >> -exponent);
+ } else {
+ if (exponent > 31) return 0;
+ return d.Sign() * static_cast<int32_t>(d.Significand() << exponent);
+ }
}
diff --git a/src/conversions.cc b/src/conversions.cc
index c34fe51..5bfddd0 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -26,11 +26,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
+#include <math.h>
#include <limits.h>
#include "conversions-inl.h"
#include "dtoa.h"
-#include "scanner-base.h"
#include "strtod.h"
#include "utils.h"
@@ -38,7 +38,6 @@
namespace internal {
-
double StringToDouble(UnicodeCache* unicode_cache,
const char* str, int flags, double empty_string_val) {
const char* end = str + StrLength(str);
@@ -390,7 +389,7 @@
int integer_pos = kBufferSize - 2;
do {
integer_buffer[integer_pos--] =
- chars[static_cast<int>(modulo(integer_part, radix))];
+ chars[static_cast<int>(fmod(integer_part, radix))];
integer_part /= radix;
} while (integer_part >= 1.0);
// Sanity check.
diff --git a/src/conversions.h b/src/conversions.h
index 9c0b8f3..e51ad65 100644
--- a/src/conversions.h
+++ b/src/conversions.h
@@ -28,12 +28,15 @@
#ifndef V8_CONVERSIONS_H_
#define V8_CONVERSIONS_H_
-#include "scanner-base.h"
+#include <limits>
+
#include "utils.h"
namespace v8 {
namespace internal {
+class UnicodeCache;
+
// Maximum number of significant digits in decimal representation.
// The longest possible double in decimal representation is
// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
@@ -44,14 +47,14 @@
const int kMaxSignificantDigits = 772;
-static bool isDigit(int x, int radix) {
+static inline bool isDigit(int x, int radix) {
return (x >= '0' && x <= '9' && x < '0' + radix)
|| (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
|| (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
}
-static double SignedZero(bool negative) {
+static inline double SignedZero(bool negative) {
return negative ? -0.0 : 0.0;
}
@@ -124,6 +127,8 @@
int flags,
double empty_string_val = 0);
+const int kDoubleToCStringMinBufferSize = 100;
+
// Converts a double to a string value according to ECMA-262 9.8.1.
// The buffer should be large enough for any floating point number.
// 100 characters is enough.
diff --git a/src/cpu-profiler-inl.h b/src/cpu-profiler-inl.h
index 938b632..4982197 100644
--- a/src/cpu-profiler-inl.h
+++ b/src/cpu-profiler-inl.h
@@ -51,11 +51,6 @@
}
-void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
- code_map->DeleteCode(start);
-}
-
-
void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->MoveCode(from, to);
}
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index 8b3333e..d74c034 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -137,16 +137,6 @@
}
-void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
- CodeEventsContainer evt_rec;
- CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
- rec->type = CodeEventRecord::CODE_DELETE;
- rec->order = ++enqueue_order_;
- rec->start = from;
- events_buffer_.Enqueue(evt_rec);
-}
-
-
void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
Address to) {
CodeEventsContainer evt_rec;
@@ -425,7 +415,6 @@
void CpuProfiler::CodeDeleteEvent(Address from) {
- Isolate::Current()->cpu_profiler()->processor_->CodeDeleteEvent(from);
}
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 4175e8f..a71c0e0 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -48,7 +48,6 @@
#define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \
V(CODE_MOVE, CodeMoveEventRecord) \
- V(CODE_DELETE, CodeDeleteEventRecord) \
V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
@@ -87,14 +86,6 @@
};
-class CodeDeleteEventRecord : public CodeEventRecord {
- public:
- Address start;
-
- INLINE(void UpdateCodeMap(CodeMap* code_map));
-};
-
-
class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
public:
Address from;
diff --git a/src/d8-debug.cc b/src/d8-debug.cc
index 0662205..adefba7 100644
--- a/src/d8-debug.cc
+++ b/src/d8-debug.cc
@@ -221,14 +221,14 @@
}
-void RemoteDebugger::MessageReceived(i::SmartPointer<char> message) {
+void RemoteDebugger::MessageReceived(i::SmartArrayPointer<char> message) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
AddEvent(event);
}
-void RemoteDebugger::KeyboardCommand(i::SmartPointer<char> command) {
+void RemoteDebugger::KeyboardCommand(i::SmartArrayPointer<char> command) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
AddEvent(event);
@@ -238,7 +238,7 @@
void RemoteDebugger::ConnectionClosed() {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
- i::SmartPointer<char>());
+ i::SmartArrayPointer<char>());
AddEvent(event);
}
@@ -330,14 +330,14 @@
void ReceiverThread::Run() {
// Receive the connect message (with empty body).
- i::SmartPointer<char> message =
- i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
+ i::SmartArrayPointer<char> message =
+ i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
ASSERT(*message == NULL);
while (true) {
// Receive a message.
- i::SmartPointer<char> message =
- i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
+ i::SmartArrayPointer<char> message =
+ i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
if (*message == NULL) {
remote_debugger_->ConnectionClosed();
return;
@@ -361,7 +361,7 @@
// Pass the keyboard command to the main thread.
remote_debugger_->KeyboardCommand(
- i::SmartPointer<char>(i::StrDup(command)));
+ i::SmartArrayPointer<char>(i::StrDup(command)));
}
}
diff --git a/src/d8-debug.h b/src/d8-debug.h
index 4e33e6f..aeff3c1 100644
--- a/src/d8-debug.h
+++ b/src/d8-debug.h
@@ -61,8 +61,8 @@
void Run();
// Handle events from the subordinate threads.
- void MessageReceived(i::SmartPointer<char> message);
- void KeyboardCommand(i::SmartPointer<char> command);
+ void MessageReceived(i::SmartArrayPointer<char> message);
+ void KeyboardCommand(i::SmartArrayPointer<char> command);
void ConnectionClosed();
private:
@@ -127,7 +127,7 @@
// Events processed by the main deubgger thread.
class RemoteDebuggerEvent {
public:
- RemoteDebuggerEvent(int type, i::SmartPointer<char> data)
+ RemoteDebuggerEvent(int type, i::SmartArrayPointer<char> data)
: type_(type), data_(data), next_(NULL) {
ASSERT(type == kMessage || type == kKeyboard || type == kDisconnect);
}
@@ -144,7 +144,7 @@
RemoteDebuggerEvent* next() { return next_; }
int type_;
- i::SmartPointer<char> data_;
+ i::SmartArrayPointer<char> data_;
RemoteDebuggerEvent* next_;
friend class RemoteDebugger;
diff --git a/src/d8-posix.cc b/src/d8-posix.cc
index 658fd4f..289c3b0 100644
--- a/src/d8-posix.cc
+++ b/src/d8-posix.cc
@@ -231,6 +231,7 @@
static const unsigned kMaxArgs = 1000;
char** arg_array() { return exec_args_; }
char* arg0() { return exec_args_[0]; }
+
private:
char* exec_args_[kMaxArgs + 1];
};
diff --git a/src/d8-readline.cc b/src/d8-readline.cc
index 08395e5..71be933 100644
--- a/src/d8-readline.cc
+++ b/src/d8-readline.cc
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -49,7 +49,7 @@
class ReadLineEditor: public LineEditor {
public:
ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
- virtual i::SmartPointer<char> Prompt(const char* prompt);
+ virtual i::SmartArrayPointer<char> Prompt(const char* prompt);
virtual bool Open();
virtual bool Close();
virtual void AddHistory(const char* str);
@@ -72,6 +72,7 @@
rl_completer_word_break_characters = kWordBreakCharacters;
rl_bind_key('\t', rl_complete);
using_history();
+ stifle_history(Shell::kMaxHistoryEntries);
return read_history(Shell::kHistoryFileName) == 0;
}
@@ -81,13 +82,25 @@
}
-i::SmartPointer<char> ReadLineEditor::Prompt(const char* prompt) {
+i::SmartArrayPointer<char> ReadLineEditor::Prompt(const char* prompt) {
char* result = readline(prompt);
- return i::SmartPointer<char>(result);
+ return i::SmartArrayPointer<char>(result);
}
void ReadLineEditor::AddHistory(const char* str) {
+ // Do not record empty input.
+ if (strlen(str) == 0) return;
+ // Remove duplicate history entry.
+ history_set_pos(history_length-1);
+ if (current_history()) {
+ do {
+ if (strcmp(current_history()->line, str) == 0) {
+ remove_history(where_history());
+ break;
+ }
+ } while (previous_history());
+ }
add_history(str);
}
@@ -105,7 +118,7 @@
static unsigned current_index;
static Persistent<Array> current_completions;
if (state == 0) {
- i::SmartPointer<char> full_text(i::StrNDup(rl_line_buffer, rl_point));
+ i::SmartArrayPointer<char> full_text(i::StrNDup(rl_line_buffer, rl_point));
HandleScope scope;
Handle<Array> completions =
Shell::GetCompletions(String::New(text), String::New(*full_text));
diff --git a/src/d8.cc b/src/d8.cc
index 4d7e988..55f0d4c 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -70,6 +70,7 @@
#ifndef V8_SHARED
LineEditor *LineEditor::first_ = NULL;
const char* Shell::kHistoryFileName = ".d8_history";
+const int Shell::kMaxHistoryEntries = 1000;
LineEditor::LineEditor(Type type, const char* name)
@@ -95,19 +96,19 @@
class DumbLineEditor: public LineEditor {
public:
DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
- virtual i::SmartPointer<char> Prompt(const char* prompt);
+ virtual i::SmartArrayPointer<char> Prompt(const char* prompt);
};
static DumbLineEditor dumb_line_editor;
-i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
+i::SmartArrayPointer<char> DumbLineEditor::Prompt(const char* prompt) {
static const int kBufferSize = 256;
char buffer[kBufferSize];
printf("%s", prompt);
char* str = fgets(buffer, kBufferSize, stdin);
- return i::SmartPointer<char>(str ? i::StrDup(str) : str);
+ return i::SmartArrayPointer<char>(str ? i::StrDup(str) : str);
}
@@ -117,6 +118,7 @@
CounterCollection* Shell::counters_ = &local_counters_;
i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
Persistent<Context> Shell::utility_context_;
+LineEditor* Shell::console = NULL;
#endif // V8_SHARED
Persistent<Context> Shell::evaluation_context_;
@@ -176,8 +178,8 @@
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(result);
- const char* cstr = ToCString(str);
- printf("%s\n", cstr);
+ fwrite(*str, sizeof(**str), str.length(), stdout);
+ printf("\n");
}
return true;
}
@@ -203,13 +205,25 @@
int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
if (n != str.length()) {
printf("Error in fwrite\n");
- exit(1);
+ Exit(1);
}
}
return Undefined();
}
+Handle<Value> Shell::EnableProfiler(const Arguments& args) {
+ V8::ResumeProfiler();
+ return Undefined();
+}
+
+
+Handle<Value> Shell::DisableProfiler(const Arguments& args) {
+ V8::PauseProfiler();
+ return Undefined();
+}
+
+
Handle<Value> Shell::Read(const Arguments& args) {
String::Utf8Value file(args[0]);
if (*file == NULL) {
@@ -259,7 +273,7 @@
if (source.IsEmpty()) {
return ThrowException(String::New("Error loading file"));
}
- if (!ExecuteString(source, String::New(*file), false, false)) {
+ if (!ExecuteString(source, String::New(*file), false, true)) {
return ThrowException(String::New("Error executing file"));
}
}
@@ -283,18 +297,20 @@
size_t length = 0;
if (args[0]->IsUint32()) {
length = args[0]->Uint32Value();
- } else if (args[0]->IsNumber()) {
- double raw_length = args[0]->NumberValue();
+ } else {
+ Local<Number> number = args[0]->ToNumber();
+ if (number.IsEmpty() || !number->IsNumber()) {
+ return ThrowException(String::New("Array length must be a number."));
+ }
+ int32_t raw_length = number->ToInt32()->Int32Value();
if (raw_length < 0) {
return ThrowException(String::New("Array length must not be negative."));
}
- if (raw_length > kMaxLength) {
+ if (raw_length > static_cast<int32_t>(kMaxLength)) {
return ThrowException(
String::New("Array length exceeds maximum length."));
}
length = static_cast<size_t>(raw_length);
- } else {
- return ThrowException(String::New("Array length must be a number."));
}
if (length > static_cast<size_t>(kMaxLength)) {
return ThrowException(String::New("Array length exceeds maximum length."));
@@ -427,6 +443,7 @@
printf("%s\n", stack_trace_string);
}
}
+ printf("\n");
}
@@ -506,7 +523,7 @@
NULL : counters_file_->memory();
if (memory == NULL) {
printf("Could not map counters file %s\n", name);
- exit(1);
+ Exit(1);
}
counters_ = static_cast<CounterCollection*>(memory);
V8::SetCounterFunction(LookupCounter);
@@ -656,6 +673,10 @@
global_template->Set(String::New("load"), FunctionTemplate::New(Load));
global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
global_template->Set(String::New("version"), FunctionTemplate::New(Version));
+ global_template->Set(String::New("enableProfiler"),
+ FunctionTemplate::New(EnableProfiler));
+ global_template->Set(String::New("disableProfiler"),
+ FunctionTemplate::New(DisableProfiler));
// Bind the handlers for external arrays.
global_template->Set(String::New("Int8Array"),
@@ -683,7 +704,7 @@
global_template->Set(String::New("lol_is_enabled"), False());
#endif
-#ifndef V8_SHARED
+#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
AddOSMethods(os_templ);
global_template->Set(String::New("os"), os_templ);
@@ -699,7 +720,7 @@
int bz2_result = startup_data_decompressor.Decompress();
if (bz2_result != BZ_OK) {
fprintf(stderr, "bzip error code: %d\n", bz2_result);
- exit(1);
+ Exit(1);
}
#endif
@@ -761,8 +782,18 @@
}
+void Shell::Exit(int exit_code) {
+ // Use _exit instead of exit to avoid races between isolate
+ // threads and static destructors.
+ fflush(stdout);
+ fflush(stderr);
+ _exit(exit_code);
+}
+
+
#ifndef V8_SHARED
void Shell::OnExit() {
+ if (console != NULL) console->Close();
if (i::FLAG_dump_counters) {
printf("+----------------------------------------+-------------+\n");
printf("| Name | Value |\n");
@@ -864,22 +895,22 @@
void Shell::RunShell() {
Locker locker;
Context::Scope context_scope(evaluation_context_);
- HandleScope handle_scope;
+ HandleScope outer_scope;
Handle<String> name = String::New("(d8)");
#ifndef V8_SHARED
- LineEditor* editor = LineEditor::Get();
- printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
+ console = LineEditor::Get();
+ printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
if (i::FLAG_debugger) {
printf("JavaScript debugger enabled\n");
}
- editor->Open();
+ console->Open();
while (true) {
- i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
+ i::SmartArrayPointer<char> input = console->Prompt(Shell::kPrompt);
if (input.is_empty()) break;
- editor->AddHistory(*input);
+ console->AddHistory(*input);
+ HandleScope inner_scope;
ExecuteString(String::New(*input), name, true, true);
}
- editor->Close();
#else
printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
static const int kBufferSize = 256;
@@ -887,6 +918,7 @@
char buffer[kBufferSize];
printf("%s", Shell::kPrompt);
if (fgets(buffer, kBufferSize, stdin) == NULL) break;
+ HandleScope inner_scope;
ExecuteString(String::New(buffer), name, true, true);
}
#endif // V8_SHARED
@@ -897,18 +929,24 @@
#ifndef V8_SHARED
class ShellThread : public i::Thread {
public:
- ShellThread(int no, i::Vector<const char> files)
+ // Takes ownership of the underlying char array of |files|.
+ ShellThread(int no, char* files)
: Thread("d8:ShellThread"),
no_(no), files_(files) { }
+
+ ~ShellThread() {
+ delete[] files_;
+ }
+
virtual void Run();
private:
int no_;
- i::Vector<const char> files_;
+ char* files_;
};
void ShellThread::Run() {
- char* ptr = const_cast<char*>(files_.start());
+ char* ptr = files_;
while ((ptr != NULL) && (*ptr != '\0')) {
// For each newline-separated line.
char* next_line = ReadLine(ptr);
@@ -921,23 +959,24 @@
// Prepare the context for this thread.
Locker locker;
- HandleScope scope;
+ HandleScope outer_scope;
Persistent<Context> thread_context = Shell::CreateEvaluationContext();
Context::Scope context_scope(thread_context);
while ((ptr != NULL) && (*ptr != '\0')) {
+ HandleScope inner_scope;
char* filename = ptr;
ptr = ReadWord(ptr);
// Skip empty strings.
if (strlen(filename) == 0) {
- break;
+ continue;
}
Handle<String> str = Shell::ReadFile(filename);
if (str.IsEmpty()) {
- printf("WARNING: %s not found\n", filename);
- break;
+ printf("File '%s' not found\n", filename);
+ Shell::Exit(1);
}
Shell::ExecuteString(str, String::New(filename), false, false);
@@ -950,12 +989,15 @@
#endif // V8_SHARED
-void SourceGroup::ExitShell(int exit_code) {
- // Use _exit instead of exit to avoid races between isolate
- // threads and static destructors.
- fflush(stdout);
- fflush(stderr);
- _exit(exit_code);
+SourceGroup::~SourceGroup() {
+#ifndef V8_SHARED
+ delete next_semaphore_;
+ next_semaphore_ = NULL;
+ delete done_semaphore_;
+ done_semaphore_ = NULL;
+ delete thread_;
+ thread_ = NULL;
+#endif // V8_SHARED
}
@@ -968,8 +1010,7 @@
Handle<String> file_name = String::New("unnamed");
Handle<String> source = String::New(argv_[i + 1]);
if (!Shell::ExecuteString(source, file_name, false, true)) {
- ExitShell(1);
- return;
+ Shell::Exit(1);
}
++i;
} else if (arg[0] == '-') {
@@ -981,12 +1022,10 @@
Handle<String> source = ReadFile(arg);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", arg);
- ExitShell(1);
- return;
+ Shell::Exit(1);
}
if (!Shell::ExecuteString(source, file_name, false, true)) {
- ExitShell(1);
- return;
+ Shell::Exit(1);
}
}
}
@@ -1050,7 +1089,6 @@
if (thread_ == NULL) return;
if (Shell::options.last_run) {
thread_->Join();
- thread_ = NULL;
} else {
done_semaphore_->Wait();
}
@@ -1123,14 +1161,18 @@
return false;
#endif // V8_SHARED
options.num_isolates++;
+ } else if (strcmp(argv[i], "-p") == 0) {
+#ifdef V8_SHARED
+ printf("D8 with shared library does not support multi-threading\n");
+ return false;
+#else
+ options.num_parallel_files++;
+#endif // V8_SHARED
}
#ifdef V8_SHARED
else if (strcmp(argv[i], "--dump-counters") == 0) {
printf("D8 with shared library does not include counters\n");
return false;
- } else if (strcmp(argv[i], "-p") == 0) {
- printf("D8 with shared library does not support multi-threading\n");
- return false;
} else if (strcmp(argv[i], "--debugger") == 0) {
printf("Javascript debugger not included\n");
return false;
@@ -1140,6 +1182,8 @@
#ifndef V8_SHARED
// Run parallel threads if we are not using --isolate
+ options.parallel_files = new char*[options.num_parallel_files];
+ int parallel_files_set = 0;
for (int i = 1; i < argc; i++) {
if (argv[i] == NULL) continue;
if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
@@ -1148,25 +1192,21 @@
return false;
}
argv[i] = NULL;
- if (options.parallel_files == NULL) {
- options.parallel_files = new i::List<i::Vector<const char> >();
- }
- int size = 0;
- const char* files = ReadChars(argv[++i], &size);
- if (files == NULL) {
- printf("-p option incomplete\n");
- return false;
- }
+ i++;
+ options.parallel_files[parallel_files_set] = argv[i];
+ parallel_files_set++;
argv[i] = NULL;
- options.parallel_files->Add(i::Vector<const char>(files, size));
- delete[] files;
}
}
+ if (parallel_files_set != options.num_parallel_files) {
+ printf("-p requires a file containing a list of files as parameter\n");
+ return false;
+ }
#endif // V8_SHARED
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
- // set up isolated source groups
+ // Set up isolated source groups.
options.isolate_sources = new SourceGroup[options.num_isolates];
SourceGroup* current = options.isolate_sources;
current->Begin(argv, 1);
@@ -1189,14 +1229,22 @@
int Shell::RunMain(int argc, char* argv[]) {
#ifndef V8_SHARED
i::List<i::Thread*> threads(1);
- if (options.parallel_files != NULL)
- for (int i = 0; i < options.parallel_files->length(); i++) {
- i::Vector<const char> files = options.parallel_files->at(i);
+ if (options.parallel_files != NULL) {
+ for (int i = 0; i < options.num_parallel_files; i++) {
+ char* files = NULL;
+ { Locker lock(Isolate::GetCurrent());
+ int size = 0;
+ files = ReadChars(options.parallel_files[i], &size);
+ }
+ if (files == NULL) {
+ printf("File list '%s' not found\n", options.parallel_files[i]);
+ Exit(1);
+ }
ShellThread* thread = new ShellThread(threads.length(), files);
thread->Start();
threads.Add(thread);
}
-
+ }
for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].StartExecuteInThread();
}
@@ -1205,29 +1253,20 @@
Locker lock;
HandleScope scope;
Persistent<Context> context = CreateEvaluationContext();
- if (options.last_run) {
- // Keep using the same context in the interactive shell.
- evaluation_context_ = context;
-#ifndef V8_SHARED
- // If the interactive debugger is enabled make sure to activate
- // it before running the files passed on the command line.
- if (i::FLAG_debugger) {
- InstallUtilityScript();
- }
-#endif // V8_SHARED
- }
{
Context::Scope cscope(context);
options.isolate_sources[0].Execute();
}
- if (!options.last_run) {
+ if (options.last_run) {
+ // Keep using the same context in the interactive shell
+ evaluation_context_ = context;
+ } else {
context.Dispose();
}
#ifndef V8_SHARED
// Start preemption if threads have been created and preemption is enabled.
- if (options.parallel_files != NULL
- && threads.length() > 0
+ if (threads.length() > 0
&& options.use_preemption) {
Locker::StartPreemption(options.preemption_interval);
}
@@ -1239,12 +1278,16 @@
options.isolate_sources[i].WaitForThread();
}
- if (options.parallel_files != NULL)
- for (int i = 0; i < threads.length(); i++) {
- i::Thread* thread = threads[i];
- thread->Join();
- delete thread;
- }
+ for (int i = 0; i < threads.length(); i++) {
+ i::Thread* thread = threads[i];
+ thread->Join();
+ delete thread;
+ }
+
+ if (threads.length() > 0 && options.use_preemption) {
+ Locker lock;
+ Locker::StopPreemption();
+ }
#endif // V8_SHARED
return 0;
}
@@ -1289,9 +1332,7 @@
|| !options.script_executed )
&& !options.test_shell ) {
#ifndef V8_SHARED
- if (!i::FLAG_debugger) {
- InstallUtilityScript();
- }
+ InstallUtilityScript();
#endif // V8_SHARED
RunShell();
}
diff --git a/src/d8.h b/src/d8.h
index 28321f5..15d8d5d 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -28,11 +28,11 @@
#ifndef V8_D8_H_
#define V8_D8_H_
-
#ifndef V8_SHARED
-#include "v8.h"
#include "allocation.h"
#include "hashmap.h"
+#include "smart-array-pointer.h"
+#include "v8.h"
#else
#include "../include/v8.h"
#endif // V8_SHARED
@@ -116,6 +116,29 @@
#endif // V8_SHARED
+#ifndef V8_SHARED
+class LineEditor {
+ public:
+ enum Type { DUMB = 0, READLINE = 1 };
+ LineEditor(Type type, const char* name);
+ virtual ~LineEditor() { }
+
+ virtual i::SmartArrayPointer<char> Prompt(const char* prompt) = 0;
+ virtual bool Open() { return true; }
+ virtual bool Close() { return true; }
+ virtual void AddHistory(const char* str) { }
+
+ const char* name() { return name_; }
+ static LineEditor* Get();
+ private:
+ Type type_;
+ const char* name_;
+ LineEditor* next_;
+ static LineEditor* first_;
+};
+#endif // V8_SHARED
+
+
class SourceGroup {
public:
SourceGroup() :
@@ -126,7 +149,9 @@
#endif // V8_SHARED
argv_(NULL),
begin_offset_(0),
- end_offset_(0) { }
+ end_offset_(0) {}
+
+ ~SourceGroup();
void Begin(char** argv, int offset) {
argv_ = const_cast<const char**>(argv);
@@ -178,6 +203,7 @@
#ifndef V8_SHARED
use_preemption(true),
preemption_interval(10),
+ num_parallel_files(0),
parallel_files(NULL),
#endif // V8_SHARED
script_executed(false),
@@ -189,10 +215,18 @@
num_isolates(1),
isolate_sources(NULL) { }
+ ~ShellOptions() {
+#ifndef V8_SHARED
+ delete[] parallel_files;
+#endif // V8_SHARED
+ delete[] isolate_sources;
+ }
+
#ifndef V8_SHARED
bool use_preemption;
int preemption_interval;
- i::List< i::Vector<const char> >* parallel_files;
+ int num_parallel_files;
+ char** parallel_files;
#endif // V8_SHARED
bool script_executed;
bool last_run;
@@ -209,6 +243,7 @@
#else
class Shell : public i::AllStatic {
#endif // V8_SHARED
+
public:
static bool ExecuteString(Handle<String> source,
Handle<Value> name,
@@ -220,6 +255,7 @@
static Persistent<Context> CreateEvaluationContext();
static int RunMain(int argc, char* argv[]);
static int Main(int argc, char* argv[]);
+ static void Exit(int exit_code);
#ifndef V8_SHARED
static Handle<Array> GetCompletions(Handle<String> text,
@@ -248,6 +284,8 @@
static Handle<Value> Yield(const Arguments& args);
static Handle<Value> Quit(const Arguments& args);
static Handle<Value> Version(const Arguments& args);
+ static Handle<Value> EnableProfiler(const Arguments& args);
+ static Handle<Value> DisableProfiler(const Arguments& args);
static Handle<Value> Read(const Arguments& args);
static Handle<Value> ReadLine(const Arguments& args);
static Handle<Value> Load(const Arguments& args);
@@ -298,6 +336,8 @@
static void AddOSMethods(Handle<ObjectTemplate> os_template);
#ifndef V8_SHARED
static const char* kHistoryFileName;
+ static const int kMaxHistoryEntries;
+ static LineEditor* console;
#endif // V8_SHARED
static const char* kPrompt;
static ShellOptions options;
@@ -328,29 +368,6 @@
};
-#ifndef V8_SHARED
-class LineEditor {
- public:
- enum Type { DUMB = 0, READLINE = 1 };
- LineEditor(Type type, const char* name);
- virtual ~LineEditor() { }
-
- virtual i::SmartPointer<char> Prompt(const char* prompt) = 0;
- virtual bool Open() { return true; }
- virtual bool Close() { return true; }
- virtual void AddHistory(const char* str) { }
-
- const char* name() { return name_; }
- static LineEditor* Get();
- private:
- Type type_;
- const char* name_;
- LineEditor* next_;
- static LineEditor* first_;
-};
-#endif // V8_SHARED
-
-
} // namespace v8
diff --git a/src/d8.js b/src/d8.js
index a2b9585..3009037 100644
--- a/src/d8.js
+++ b/src/d8.js
@@ -1786,7 +1786,7 @@
function decodeLolListResponse(body, title) {
-
+
var result;
var total_count = body.count;
var total_size = body.size;
diff --git a/src/date.js b/src/date.js
index 79b846d..ccefce5 100644
--- a/src/date.js
+++ b/src/date.js
@@ -1048,18 +1048,19 @@
// -------------------------------------------------------------------
-function SetupDate() {
- // Setup non-enumerable properties of the Date object itself.
+function SetUpDate() {
+ %CheckIsBootstrapping();
+ // Set up non-enumerable properties of the Date object itself.
InstallFunctions($Date, DONT_ENUM, $Array(
"UTC", DateUTC,
"parse", DateParse,
"now", DateNow
));
- // Setup non-enumerable constructor property of the Date prototype object.
+ // Set up non-enumerable constructor property of the Date prototype object.
%SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
- // Setup non-enumerable functions of the Date prototype object and
+ // Set up non-enumerable functions of the Date prototype object and
// set their names.
InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
"toString", DateToString,
@@ -1111,4 +1112,4 @@
));
}
-SetupDate();
+SetUpDate();
diff --git a/src/dateparser.h b/src/dateparser.h
index 4bd320e..27584ce 100644
--- a/src/dateparser.h
+++ b/src/dateparser.h
@@ -30,14 +30,12 @@
#include "allocation.h"
#include "char-predicates-inl.h"
-#include "scanner-base.h"
namespace v8 {
namespace internal {
class DateParser : public AllStatic {
public:
-
// Parse the string as a date. If parsing succeeds, return true after
// filling out the output array as follows (all integers are Smis):
// [0]: year
@@ -235,6 +233,7 @@
static DateToken Invalid() {
return DateToken(kInvalidTokenTag, 0, -1);
}
+
private:
enum TagType {
kInvalidTokenTag = -6,
@@ -276,6 +275,7 @@
}
return false;
}
+
private:
DateToken Scan();
@@ -352,6 +352,7 @@
static bool IsMinute(int x) { return Between(x, 0, 59); }
static bool IsHour(int x) { return Between(x, 0, 23); }
static bool IsSecond(int x) { return Between(x, 0, 59); }
+
private:
static bool IsHour12(int x) { return Between(x, 0, 12); }
static bool IsMillisecond(int x) { return Between(x, 0, 999); }
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index 520bc62..591d0b3 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -169,7 +169,8 @@
while (true) {
// Read data from the debugger front end.
- SmartPointer<char> message = DebuggerAgentUtil::ReceiveMessage(client_);
+ SmartArrayPointer<char> message =
+ DebuggerAgentUtil::ReceiveMessage(client_);
const char* msg = *message;
bool is_closing_session = (msg == NULL);
@@ -232,7 +233,7 @@
StrLength(kContentLength);
-SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
+SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
int received;
// Read header.
@@ -250,7 +251,7 @@
received = conn->Receive(&c, 1);
if (received <= 0) {
PrintF("Error %d\n", Socket::LastError());
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
// Add character to header buffer.
@@ -287,12 +288,12 @@
if (strcmp(key, kContentLength) == 0) {
// Get the content length value if present and within a sensible range.
if (value == NULL || strlen(value) > 7) {
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
for (int i = 0; value[i] != '\0'; i++) {
// Bail out if illegal data.
if (value[i] < '0' || value[i] > '9') {
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
content_length = 10 * content_length + (value[i] - '0');
}
@@ -304,7 +305,7 @@
// Return now if no body.
if (content_length == 0) {
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
// Read body.
@@ -312,11 +313,11 @@
received = ReceiveAll(conn, buffer, content_length);
if (received < content_length) {
PrintF("Error %d\n", Socket::LastError());
- return SmartPointer<char>();
+ return SmartArrayPointer<char>();
}
buffer[content_length] = '\0';
- return SmartPointer<char>(buffer);
+ return SmartArrayPointer<char>(buffer);
}
diff --git a/src/debug-agent.h b/src/debug-agent.h
index e167871..a07fb0f 100644
--- a/src/debug-agent.h
+++ b/src/debug-agent.h
@@ -72,7 +72,7 @@
void OnSessionClosed(DebuggerAgentSession* session);
Isolate* isolate_;
- SmartPointer<const char> name_; // Name of the embedding application.
+ SmartArrayPointer<const char> name_; // Name of the embedding application.
int port_; // Port to use for the agent.
Socket* server_; // Server socket for listen/accept.
bool terminate_; // Termination flag.
@@ -117,7 +117,7 @@
static const char* const kContentLength;
static const int kContentLengthSize;
- static SmartPointer<char> ReceiveMessage(const Socket* conn);
+ static SmartArrayPointer<char> ReceiveMessage(const Socket* conn);
static bool SendConnectMessage(const Socket* conn,
const char* embedding_host);
static bool SendMessage(const Socket* conn, const Vector<uint16_t> message);
diff --git a/src/debug.cc b/src/debug.cc
index 2d58ce1..20cd802 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -40,6 +40,7 @@
#include "global-handles.h"
#include "ic.h"
#include "ic-inl.h"
+#include "list.h"
#include "messages.h"
#include "natives.h"
#include "stub-cache.h"
@@ -542,6 +543,7 @@
thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
thread_local_.step_count_ = 0;
thread_local_.last_fp_ = 0;
+ thread_local_.queued_step_count_ = 0;
thread_local_.step_into_fp_ = 0;
thread_local_.step_out_fp_ = 0;
thread_local_.after_break_target_ = 0;
@@ -957,14 +959,49 @@
// Clear all current stepping setup.
ClearStepping();
- // Notify the debug event listeners.
- isolate_->debugger()->OnDebugBreak(break_points_hit, false);
+ if (thread_local_.queued_step_count_ > 0) {
+ // Perform queued steps
+ int step_count = thread_local_.queued_step_count_;
+
+ // Clear queue
+ thread_local_.queued_step_count_ = 0;
+
+ PrepareStep(StepNext, step_count);
+ } else {
+ // Notify the debug event listeners.
+ isolate_->debugger()->OnDebugBreak(break_points_hit, false);
+ }
} else if (thread_local_.last_step_action_ != StepNone) {
// Hold on to last step action as it is cleared by the call to
// ClearStepping.
StepAction step_action = thread_local_.last_step_action_;
int step_count = thread_local_.step_count_;
+ // If StepNext goes deeper in code, StepOut until original frame
+ // and keep step count queued up in the meantime.
+ if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) {
+ // Count frames until target frame
+ int count = 0;
+ JavaScriptFrameIterator it(isolate_);
+ while (!it.done() && it.frame()->fp() != thread_local_.last_fp_) {
+ count++;
+ it.Advance();
+ }
+
+ // If we found original frame
+ if (it.frame()->fp() == thread_local_.last_fp_) {
+ if (step_count > 1) {
+ // Save old count and action to continue stepping after
+ // StepOut
+ thread_local_.queued_step_count_ = step_count - 1;
+ }
+
+ // Set up for StepOut to reach target frame
+ step_action = StepOut;
+ step_count = count;
+ }
+ }
+
// Clear all current stepping setup.
ClearStepping();
@@ -1105,6 +1142,8 @@
int* source_position) {
HandleScope scope(isolate_);
+ PrepareForBreakPoints();
+
if (!EnsureDebugInfo(shared)) {
// Return if retrieving debug info failed.
return;
@@ -1178,6 +1217,7 @@
void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
+ PrepareForBreakPoints();
// Make sure the function has setup the debug info.
if (!EnsureDebugInfo(shared)) {
// Return if we failed to retrieve the debug info.
@@ -1234,6 +1274,9 @@
void Debug::PrepareStep(StepAction step_action, int step_count) {
HandleScope scope(isolate_);
+
+ PrepareForBreakPoints();
+
ASSERT(Debug::InDebugger());
// Remember this step action and count.
@@ -1448,6 +1491,13 @@
// steps before reporting break back to the debugger.
bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
JavaScriptFrame* frame) {
+ // StepNext and StepOut shouldn't bring us deeper in code, so last frame
+ // shouldn't be a parent of current frame.
+ if (thread_local_.last_step_action_ == StepNext ||
+ thread_local_.last_step_action_ == StepOut) {
+ if (frame->fp() < thread_local_.last_fp_) return true;
+ }
+
// If the step last action was step next or step in make sure that a new
// statement is hit.
if (thread_local_.last_step_action_ == StepNext ||
@@ -1676,19 +1726,25 @@
}
-// Ensures the debug information is present for shared.
-bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
- // Return if we already have the debug info for shared.
- if (HasDebugInfo(shared)) return true;
-
- // Ensure shared in compiled. Return false if this failed.
- if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
-
+void Debug::PrepareForBreakPoints() {
// If preparing for the first break point make sure to deoptimize all
// functions as debugging does not work with optimized code.
if (!has_break_points_) {
Deoptimizer::DeoptimizeAll();
}
+}
+
+
+// Ensures the debug information is present for shared.
+bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
+ // Return if we already have the debug info for shared.
+ if (HasDebugInfo(shared)) {
+ ASSERT(shared->is_compiled());
+ return true;
+ }
+
+ // Ensure shared in compiled. Return false if this failed.
+ if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
// Create the debug info object.
Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
@@ -1739,6 +1795,8 @@
void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
HandleScope scope(isolate_);
+ PrepareForBreakPoints();
+
// Get the executing function in which the debug break occurred.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
@@ -1829,6 +1887,8 @@
return false;
}
+ PrepareForBreakPoints();
+
// Get the executing function in which the debug break occurred.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
diff --git a/src/debug.h b/src/debug.h
index c614844..a098040 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -247,6 +247,8 @@
static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
+ void PrepareForBreakPoints();
+
// Returns whether the operation succeeded.
bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
@@ -506,6 +508,9 @@
// Frame pointer from last step next action.
Address last_fp_;
+ // Number of queued steps left to perform before debug event.
+ int queued_step_count_;
+
// Frame pointer for frame from which step in was performed.
Address step_into_fp_;
@@ -1026,6 +1031,7 @@
return NULL;
}
}
+
private:
Debug::AddressId id_;
};
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 94b2ff5..5feb73d 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -613,13 +613,11 @@
intptr_t input_value = input_->GetRegister(input_reg);
if (FLAG_trace_deopt) {
PrintF(
- " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s ",
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" V8PRIxPTR " ; %s\n",
output_[frame_index]->GetTop() + output_offset,
output_offset,
input_value,
converter.NameOfCPURegister(input_reg));
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
@@ -677,12 +675,10 @@
if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": ",
output_[frame_index]->GetTop() + output_offset);
- PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] ",
+ PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d]\n",
output_offset,
input_value,
input_offset);
- reinterpret_cast<Object*>(input_value)->ShortPrint();
- PrintF("\n");
}
output_[frame_index]->SetFrameSlot(output_offset, input_value);
return;
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 79076d6..1e67b4c 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -223,7 +223,7 @@
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
relocinfo.target_object()->ShortPrint(&accumulator);
- SmartPointer<const char> obj_name = accumulator.ToCString();
+ SmartArrayPointer<const char> obj_name = accumulator.ToCString();
out.AddFormatted(" ;; object: %s", *obj_name);
} else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
const char* reference_name =
@@ -247,9 +247,6 @@
PropertyType type = code->type();
out.AddFormatted(", %s", Code::PropertyType2String(type));
}
- if (code->ic_in_loop() == IN_LOOP) {
- out.AddFormatted(", in_loop");
- }
if (kind == Code::CALL_IC || kind == Code::KEYED_CALL_IC) {
out.AddFormatted(", argc = %d", code->arguments_count());
}
diff --git a/src/dtoa.cc b/src/dtoa.cc
index b857a5d..00233a8 100644
--- a/src/dtoa.cc
+++ b/src/dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -27,7 +27,10 @@
#include <math.h>
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
+
#include "dtoa.h"
#include "bignum-dtoa.h"
diff --git a/src/elements.cc b/src/elements.cc
index 1afc5da..e4ecfe8 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -401,7 +401,7 @@
Heap* heap = isolate->heap();
FixedArray* backing_store = FixedArray::cast(obj->elements());
bool is_arguments =
- (obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+ (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
if (is_arguments) {
backing_store = FixedArray::cast(backing_store->get(1));
}
@@ -565,28 +565,28 @@
switch (array->map()->instance_type()) {
case FIXED_ARRAY_TYPE:
if (array->IsDictionary()) {
- return elements_accessors_[JSObject::DICTIONARY_ELEMENTS];
+ return elements_accessors_[DICTIONARY_ELEMENTS];
} else {
- return elements_accessors_[JSObject::FAST_ELEMENTS];
+ return elements_accessors_[FAST_ELEMENTS];
}
case EXTERNAL_BYTE_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_BYTE_ELEMENTS];
+ return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
+ return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
case EXTERNAL_SHORT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_SHORT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
case EXTERNAL_INT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_INT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_INT_ELEMENTS];
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
case EXTERNAL_FLOAT_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_FLOAT_ELEMENTS];
+ return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
case EXTERNAL_DOUBLE_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_DOUBLE_ELEMENTS];
+ return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
case EXTERNAL_PIXEL_ARRAY_TYPE:
- return elements_accessors_[JSObject::EXTERNAL_PIXEL_ELEMENTS];
+ return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
default:
UNREACHABLE();
return NULL;
diff --git a/src/elements.h b/src/elements.h
index 3eae303..851c8c3 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -54,8 +54,8 @@
Object* receiver) = 0;
// Returns a shared ElementsAccessor for the specified ElementsKind.
- static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) {
- ASSERT(elements_kind < JSObject::kElementsKindCount);
+ static ElementsAccessor* ForKind(ElementsKind elements_kind) {
+ ASSERT(elements_kind < kElementsKindCount);
return elements_accessors_[elements_kind];
}
diff --git a/src/execution.cc b/src/execution.cc
index bdbdca8..f36d4e4 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -149,12 +149,29 @@
Handle<Object> receiver,
int argc,
Object*** args,
- bool* pending_exception) {
+ bool* pending_exception,
+ bool convert_receiver) {
if (!callable->IsJSFunction()) {
callable = TryGetFunctionDelegate(callable, pending_exception);
if (*pending_exception) return callable;
}
Handle<JSFunction> func = Handle<JSFunction>::cast(callable);
+
+ // In non-strict mode, convert receiver.
+ if (convert_receiver && !receiver->IsJSReceiver() &&
+ !func->shared()->native() && !func->shared()->strict_mode()) {
+ if (receiver->IsUndefined() || receiver->IsNull()) {
+ Object* global = func->context()->global()->global_receiver();
+ // Under some circumstances, 'global' can be the JSBuiltinsObject
+ // In that case, don't rewrite.
+ // (FWIW, the same holds for GetIsolate()->global()->global_receiver().)
+ if (!global->IsJSBuiltinsObject()) receiver = Handle<Object>(global);
+ } else {
+ receiver = ToObject(receiver, pending_exception);
+ }
+ if (*pending_exception) return callable;
+ }
+
return Invoke(false, func, receiver, argc, args, pending_exception);
}
@@ -210,10 +227,17 @@
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a function.
+ // If object is a function proxy, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_function_delegate());
}
@@ -227,10 +251,17 @@
ASSERT(!object->IsJSFunction());
Isolate* isolate = Isolate::Current();
+ // If object is a function proxy, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_function_delegate());
}
@@ -253,10 +284,17 @@
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a constructor.
+ // If object is a function proxies, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_constructor_delegate());
}
@@ -274,10 +312,17 @@
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a constructor.
+ // If object is a function proxies, get its handler. Iterate if necessary.
+ Object* fun = *object;
+ while (fun->IsJSFunctionProxy()) {
+ fun = JSFunctionProxy::cast(fun)->call_trap();
+ }
+ if (fun->IsJSFunction()) return Handle<Object>(fun);
+
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
- if (object->IsHeapObject() &&
- HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ if (fun->IsHeapObject() &&
+ HeapObject::cast(fun)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
isolate->global_context()->call_as_constructor_delegate());
}
@@ -553,7 +598,7 @@
Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) {
- if (obj->IsJSObject()) return obj;
+ if (obj->IsSpecObject()) return obj;
RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc);
}
diff --git a/src/execution.h b/src/execution.h
index bb5f804..5cd7141 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -53,11 +53,16 @@
// *pending_exception tells whether the invoke resulted in
// a pending exception.
//
+ // When convert_receiver is set, and the receiver is not an object,
+ // and the function called is not in strict mode, receiver is converted to
+ // an object.
+ //
static Handle<Object> Call(Handle<Object> callable,
Handle<Object> receiver,
int argc,
Object*** args,
- bool* pending_exception);
+ bool* pending_exception,
+ bool convert_receiver = false);
// Construct object from function, the caller supplies an array of
// arguments. Arguments are Object* type. After function returns,
diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc
index b3f83fe..9fbf329 100644
--- a/src/extensions/externalize-string-extension.cc
+++ b/src/extensions/externalize-string-extension.cc
@@ -133,9 +133,11 @@
void ExternalizeStringExtension::Register() {
- static ExternalizeStringExtension externalize_extension;
+ static ExternalizeStringExtension* externalize_extension = NULL;
+ if (externalize_extension == NULL)
+ externalize_extension = new ExternalizeStringExtension;
static v8::DeclareExtension externalize_extension_declaration(
- &externalize_extension);
+ externalize_extension);
}
} } // namespace v8::internal
diff --git a/src/factory.cc b/src/factory.cc
index ee5c37b..9728926 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -465,13 +465,13 @@
}
-Handle<Map> Factory::GetExternalArrayElementsMap(
+Handle<Map> Factory::GetElementsTransitionMap(
Handle<Map> src,
- ExternalArrayType array_type,
+ ElementsKind elements_kind,
bool safe_to_add_transition) {
CALL_HEAP_FUNCTION(isolate(),
- src->GetExternalArrayElementsMap(array_type,
- safe_to_add_transition),
+ src->GetElementsTransitionMap(elements_kind,
+ safe_to_add_transition),
Map);
}
@@ -922,10 +922,19 @@
}
-void Factory::BecomeJSObject(Handle<JSProxy> object) {
+void Factory::BecomeJSObject(Handle<JSReceiver> object) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
- isolate()->heap()->ReinitializeJSProxyAsJSObject(*object));
+ isolate()->heap()->ReinitializeJSReceiver(
+ *object, JS_OBJECT_TYPE, JSObject::kHeaderSize));
+}
+
+
+void Factory::BecomeJSFunction(Handle<JSReceiver> object) {
+ CALL_HEAP_FUNCTION_VOID(
+ isolate(),
+ isolate()->heap()->ReinitializeJSReceiver(
+ *object, JS_FUNCTION_TYPE, JSFunction::kSize));
}
diff --git a/src/factory.h b/src/factory.h
index a69b05b..71ae750 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -219,9 +219,9 @@
Handle<Map> GetSlowElementsMap(Handle<Map> map);
- Handle<Map> GetExternalArrayElementsMap(Handle<Map> map,
- ExternalArrayType array_type,
- bool safe_to_add_transition);
+ Handle<Map> GetElementsTransitionMap(Handle<Map> map,
+ ElementsKind elements_kind,
+ bool safe_to_add_transition);
Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
@@ -260,8 +260,9 @@
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
- // Change the type of the argument into a regular JS object and reinitialize.
- void BecomeJSObject(Handle<JSProxy> object);
+ // Change the type of the argument into a JS object/function and reinitialize.
+ void BecomeJSObject(Handle<JSReceiver> object);
+ void BecomeJSFunction(Handle<JSReceiver> object);
Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype);
diff --git a/src/fast-dtoa.cc b/src/fast-dtoa.cc
index c7f6aa1..e62bd01 100644
--- a/src/fast-dtoa.cc
+++ b/src/fast-dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -25,7 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
#include "fast-dtoa.h"
diff --git a/src/fixed-dtoa.cc b/src/fixed-dtoa.cc
index 8ad88f6..1fd974c 100644
--- a/src/fixed-dtoa.cc
+++ b/src/fixed-dtoa.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -27,7 +27,9 @@
#include <math.h>
-#include "v8.h"
+#include "../include/v8stdint.h"
+#include "checks.h"
+#include "utils.h"
#include "double.h"
#include "fixed-dtoa.h"
diff --git a/src/flags.cc b/src/flags.cc
index c20f5ee..ab5b57c 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -31,7 +31,7 @@
#include "v8.h"
#include "platform.h"
-#include "smart-pointer.h"
+#include "smart-array-pointer.h"
#include "string-stream.h"
@@ -193,7 +193,7 @@
}
-static SmartPointer<const char> ToString(Flag* flag) {
+static SmartArrayPointer<const char> ToString(Flag* flag) {
HeapStringAllocator string_allocator;
StringStream buffer(&string_allocator);
switch (flag->type()) {
@@ -528,7 +528,7 @@
printf("Options:\n");
for (size_t i = 0; i < num_flags; ++i) {
Flag* f = &flags[i];
- SmartPointer<const char> value = ToString(f);
+ SmartArrayPointer<const char> value = ToString(f);
printf(" --%s (%s)\n type: %s default: %s\n",
f->name(), f->comment(), Type2String(f->type()), *value);
}
diff --git a/src/frames.h b/src/frames.h
index 4f94ebc..fed11c4 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -579,6 +579,7 @@
virtual void Print(StringStream* accumulator,
PrintMode mode,
int index) const;
+
protected:
explicit ArgumentsAdaptorFrame(StackFrameIterator* iterator)
: JavaScriptFrame(iterator) { }
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index ca2026b..8073874 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -96,11 +96,6 @@
}
-void BreakableStatementChecker::VisitExitContextStatement(
- ExitContextStatement* stmt) {
-}
-
-
void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
// Switch statements breakable if the tag expression is.
Visit(stmt->tag());
@@ -190,9 +185,9 @@
void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
// If assigning to a property (including a global property) the assignment is
// breakable.
- Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+ VariableProxy* proxy = expr->target()->AsVariableProxy();
Property* prop = expr->target()->AsProperty();
- if (prop != NULL || (var != NULL && var->is_global())) {
+ if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) {
is_breakable_ = true;
return;
}
@@ -291,11 +286,13 @@
}
unsigned table_offset = cgen.EmitStackCheckTable();
- Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
+ Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
code->set_optimizable(info->IsOptimizable());
cgen.PopulateDeoptimizationData(code);
code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
+ code->set_has_debug_break_slots(
+ info->isolate()->debugger()->IsDebuggerActive());
code->set_allow_osr_at_loop_nesting_level(0);
code->set_stack_check_table_offset(table_offset);
CodeGenerator::PrintCode(code, info);
@@ -395,26 +392,6 @@
}
-int FullCodeGenerator::SlotOffset(Slot* slot) {
- ASSERT(slot != NULL);
- // Offset is negative because higher indexes are at lower addresses.
- int offset = -slot->index() * kPointerSize;
- // Adjust by a (parameter or local) base offset.
- switch (slot->type()) {
- case Slot::PARAMETER:
- offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
- break;
- case Slot::LOCAL:
- offset += JavaScriptFrameConstants::kLocal0Offset;
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- UNREACHABLE();
- }
- return offset;
-}
-
-
bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
// Inline smi case inside loops, but not division and modulo which
// are too complicated and take up too much space.
@@ -529,34 +506,21 @@
void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
int length = declarations->length();
- int globals = 0;
+ int global_count = 0;
for (int i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
- Variable* var = decl->proxy()->var();
- Slot* slot = var->AsSlot();
-
- // If it was not possible to allocate the variable at compile
- // time, we need to "declare" it at runtime to make sure it
- // actually exists in the local context.
- if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
- VisitDeclaration(decl);
- } else {
- // Count global variables and functions for later processing
- globals++;
- }
+ EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count);
}
- // Compute array of global variable and function declarations.
- // Do nothing in case of no declared global functions or variables.
- if (globals > 0) {
+ // Batch declare global functions and variables.
+ if (global_count > 0) {
Handle<FixedArray> array =
- isolate()->factory()->NewFixedArray(2 * globals, TENURED);
+ isolate()->factory()->NewFixedArray(2 * global_count, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var();
- Slot* slot = var->AsSlot();
- if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
+ if (var->IsUnallocated()) {
array->set(j++, *(var->name()));
if (decl->fun() == NULL) {
if (var->mode() == Variable::CONST) {
@@ -578,12 +542,21 @@
}
}
// Invoke the platform-dependent code generator to do the actual
- // declaration the global variables and functions.
+ // declaration the global functions and variables.
DeclareGlobals(array);
}
}
+int FullCodeGenerator::DeclareGlobalsFlags() {
+ int flags = 0;
+ if (is_eval()) flags |= kDeclareGlobalsEvalFlag;
+ if (is_strict_mode()) flags |= kDeclareGlobalsStrictModeFlag;
+ if (is_native()) flags |= kDeclareGlobalsNativeFlag;
+ return flags;
+}
+
+
void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
CodeGenerator::RecordPositions(masm_, fun->start_position());
}
@@ -842,10 +815,11 @@
void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
- Breakable nested_statement(this, stmt);
+ NestedBlock nested_block(this, stmt);
SetStatementPosition(stmt);
Scope* saved_scope = scope();
+ // Push a block context when entering a block with block scoped variables.
if (stmt->block_scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context");
scope_ = stmt->block_scope();
@@ -862,8 +836,16 @@
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements());
scope_ = saved_scope;
- __ bind(nested_statement.break_label());
+ __ bind(nested_block.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+
+ // Pop block context if necessary.
+ if (stmt->block_scope() != NULL) {
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ // Update local stack frame context field.
+ StoreToFrameField(StandardFrameConstants::kContextOffset,
+ context_register());
+ }
}
@@ -1004,17 +986,6 @@
}
-void FullCodeGenerator::VisitExitContextStatement(ExitContextStatement* stmt) {
- Comment cmnt(masm_, "[ ExitContextStatement");
- SetStatementPosition(stmt);
-
- // Pop context.
- LoadContextField(context_register(), Context::PREVIOUS_INDEX);
- // Update local stack frame context field.
- StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
-}
-
-
void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Comment cmnt(masm_, "[ DoWhileStatement");
SetStatementPosition(stmt);
@@ -1162,6 +1133,9 @@
{ WithOrCatch body(this);
Visit(stmt->catch_block());
}
+ // Restore the context.
+ LoadContextField(context_register(), Context::PREVIOUS_INDEX);
+ StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
scope_ = saved_scope;
__ jmp(&done);
diff --git a/src/full-codegen.h b/src/full-codegen.h
index 0ed26a1..803c618 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -191,6 +191,22 @@
Label continue_label_;
};
+ // A nested block statement.
+ class NestedBlock : public Breakable {
+ public:
+ NestedBlock(FullCodeGenerator* codegen, Block* block)
+ : Breakable(codegen, block) {
+ }
+ virtual ~NestedBlock() {}
+
+ virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+ if (statement()->AsBlock()->block_scope() != NULL) {
+ ++(*context_length);
+ }
+ return previous_;
+ };
+ };
+
// The try block of a try/catch statement.
class TryCatch : public NestedStatement {
public:
@@ -288,10 +304,6 @@
// with a GC-safe value.
void ClearAccumulator();
- // Compute the frame pointer relative offset for a given local or
- // parameter slot.
- int SlotOffset(Slot* slot);
-
// Determine whether or not to inline the smi case for the given
// operation.
bool ShouldInlineSmiCase(Token::Value op);
@@ -321,13 +333,29 @@
Label* fall_through);
#endif // V8_TARGET_ARCH_MIPS
- void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
- void Move(Register dst, Slot* source);
+ // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
+ // a register. Emits a context chain walk if if necessary (so does
+ // SetVar) so avoid calling both on the same variable.
+ void GetVar(Register destination, Variable* var);
- // Return an operand used to read/write to a known (ie, non-LOOKUP) slot.
- // May emit code to traverse the context chain, destroying the scratch
- // register.
- MemOperand EmitSlotSearch(Slot* slot, Register scratch);
+ // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable. If it's in
+ // the context, the write barrier will be emitted and source, scratch0,
+ // scratch1 will be clobbered. Emits a context chain walk if if necessary
+ // (so does GetVar) so avoid calling both on the same variable.
+ void SetVar(Variable* var,
+ Register source,
+ Register scratch0,
+ Register scratch1);
+
+ // An operand used to read/write a stack-allocated (PARAMETER or LOCAL)
+ // variable. Writing does not need the write barrier.
+ MemOperand StackOperand(Variable* var);
+
+ // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT)
+ // variable. May emit code to traverse the context chain, loading the
+ // found context into the scratch register. Writing to this operand will
+ // need the write barrier if location is CONTEXT.
+ MemOperand VarOperand(Variable* var, Register scratch);
// Forward the bailout responsibility for the given expression to
// the next child visited (which must be in a test context).
@@ -358,6 +386,7 @@
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void DeclareGlobals(Handle<FixedArray> pairs);
+ int DeclareGlobalsFlags();
// Try to perform a comparison as a fast inlined literal compare if
// the operands allow it. Returns true if the compare operations
@@ -402,9 +431,10 @@
// Platform-specific code for a variable, constant, or function
// declaration. Functions have an initial value.
- void EmitDeclaration(Variable* variable,
+ void EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function);
+ FunctionLiteral* function,
+ int* global_count);
// Platform-specific code for checking the stack limit at the back edge of
// a loop.
@@ -435,14 +465,14 @@
#undef EMIT_INLINE_RUNTIME_CALL
// Platform-specific code for loading variables.
- void EmitLoadGlobalSlotCheckExtensions(Slot* slot,
- TypeofState typeof_state,
- Label* slow);
- MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow);
- void EmitDynamicLoadFromSlotFastCase(Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done);
+ void EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow);
+ MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
+ void EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done);
void EmitVariableLoad(VariableProxy* proxy);
enum ResolveEvalFlag {
@@ -555,6 +585,7 @@
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
+ bool is_native() { return info_->is_native(); }
bool is_strict_mode() { return function()->strict_mode(); }
StrictModeFlag strict_mode_flag() {
return is_strict_mode() ? kStrictMode : kNonStrictMode;
@@ -618,11 +649,11 @@
// this expression context.
virtual void Plug(bool flag) const = 0;
- // Emit code to convert a pure value (in a register, slot, as a literal,
- // or on top of the stack) into the result expected according to this
- // expression context.
+ // Emit code to convert a pure value (in a register, known variable
+ // location, as a literal, or on top of the stack) into the result
+ // expected according to this expression context.
virtual void Plug(Register reg) const = 0;
- virtual void Plug(Slot* slot) const = 0;
+ virtual void Plug(Variable* var) const = 0;
virtual void Plug(Handle<Object> lit) const = 0;
virtual void Plug(Heap::RootListIndex index) const = 0;
virtual void PlugTOS() const = 0;
@@ -680,7 +711,7 @@
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
@@ -703,7 +734,7 @@
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
@@ -744,7 +775,7 @@
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
@@ -774,7 +805,7 @@
virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) const;
- virtual void Plug(Slot* slot) const;
+ virtual void Plug(Variable* var) const;
virtual void Plug(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const;
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index 4d57e25..68cb053 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -993,7 +993,7 @@
}
#endif
- SmartPointer<char> GetFilename() {
+ SmartArrayPointer<char> GetFilename() {
return String::cast(script_->name())->ToCString();
}
@@ -1991,7 +1991,7 @@
GetScriptLineNumber(script, 0);
if (!name.is_null()) {
- SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS);
AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script, info);
} else {
AddCode("", *code, GDBJITInterface::FUNCTION, *script, info);
diff --git a/src/globals.h b/src/globals.h
index 7e41f97..6c6966a 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -28,6 +28,35 @@
#ifndef V8_GLOBALS_H_
#define V8_GLOBALS_H_
+// Define V8_INFINITY
+#define V8_INFINITY INFINITY
+
+// GCC specific stuff
+#ifdef __GNUC__
+
+#define __GNUC_VERSION_FOR_INFTY__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
+
+// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
+// warning flag and certain versions of GCC due to a bug:
+// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
+// For now, we use the more involved template-based version from <limits>, but
+// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
+// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
+#if __GNUC_VERSION_FOR_INFTY__ >= 29600 && __GNUC_VERSION_FOR_INFTY__ < 40100
+#include <limits>
+#undef V8_INFINITY
+#define V8_INFINITY std::numeric_limits<double>::infinity()
+#endif
+#undef __GNUC_VERSION_FOR_INFTY__
+
+#endif // __GNUC__
+
+#ifdef _MSC_VER
+#undef V8_INFINITY
+#define V8_INFINITY HUGE_VAL
+#endif
+
+
#include "../include/v8stdint.h"
namespace v8 {
@@ -226,10 +255,6 @@
const int kBinary32MantissaBits = 23;
const int kBinary32ExponentShift = 23;
-// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
-// other bits set.
-const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
-
// ASCII/UC16 constants
// Code-point values in Unicode 4.0 are 21 bits wide.
typedef uint16_t uc16;
diff --git a/src/handles.cc b/src/handles.cc
index 8c6439b..35c363c 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -921,16 +921,13 @@
}
-static bool CompileLazyFunction(Handle<JSFunction> function,
- ClearExceptionFlag flag,
- InLoopFlag in_loop_flag) {
+bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
bool result = true;
if (function->shared()->is_compiled()) {
function->ReplaceCode(function->shared()->code());
function->shared()->set_code_age(0);
} else {
CompilationInfo info(function);
- if (in_loop_flag == IN_LOOP) info.MarkAsInLoop();
result = CompileLazyHelper(&info, flag);
ASSERT(!result || function->is_compiled());
}
@@ -938,18 +935,6 @@
}
-bool CompileLazy(Handle<JSFunction> function,
- ClearExceptionFlag flag) {
- return CompileLazyFunction(function, flag, NOT_IN_LOOP);
-}
-
-
-bool CompileLazyInLoop(Handle<JSFunction> function,
- ClearExceptionFlag flag) {
- return CompileLazyFunction(function, flag, IN_LOOP);
-}
-
-
bool CompileOptimized(Handle<JSFunction> function,
int osr_ast_id,
ClearExceptionFlag flag) {
diff --git a/src/handles.h b/src/handles.h
index 9bb3b1f..7eaf4de 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -363,8 +363,6 @@
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag);
-bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag);
-
bool CompileOptimized(Handle<JSFunction> function,
int osr_ast_id,
ClearExceptionFlag flag);
diff --git a/src/heap.cc b/src/heap.cc
index 279f30b..d018593 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -41,7 +41,6 @@
#include "natives.h"
#include "objects-visiting.h"
#include "runtime-profiler.h"
-#include "scanner-base.h"
#include "scopeinfo.h"
#include "snapshot.h"
#include "v8threads.h"
@@ -70,11 +69,11 @@
: isolate_(NULL),
// semispace_size_ should be a power of 2 and old_generation_size_ should be
// a multiple of Page::kPageSize.
-#if 0//defined(ANDROID)
+#if defined(ANDROID)
reserved_semispace_size_(2*MB),
max_semispace_size_(2*MB),
initial_semispace_size_(128*KB),
- max_old_generation_size_(512*MB),
+ max_old_generation_size_(192*MB),
max_executable_size_(max_old_generation_size_),
code_range_size_(0),
#elif defined(V8_TARGET_ARCH_X64)
@@ -842,6 +841,7 @@
isolate_->keyed_lookup_cache()->Clear();
isolate_->context_slot_cache()->Clear();
isolate_->descriptor_lookup_cache()->Clear();
+ StringSplitCache::Clear(string_split_cache());
isolate_->compilation_cache()->MarkCompactPrologue();
@@ -1627,7 +1627,7 @@
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
- map->set_elements_kind(JSObject::FAST_ELEMENTS);
+ map->set_elements_kind(FAST_ELEMENTS);
// If the map object is aligned fill the padding area with Smi 0 objects.
if (Map::kPadStart < Map::kSize) {
@@ -2223,6 +2223,13 @@
}
set_single_character_string_cache(FixedArray::cast(obj));
+ // Allocate cache for string split.
+ { MaybeObject* maybe_obj =
+ AllocateFixedArray(StringSplitCache::kStringSplitCacheSize, TENURED);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_string_split_cache(FixedArray::cast(obj));
+
// Allocate cache for external strings pointing to native source code.
{ MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
if (!maybe_obj->ToObject(&obj)) return false;
@@ -2248,6 +2255,75 @@
}
+Object* StringSplitCache::Lookup(
+ FixedArray* cache, String* string, String* pattern) {
+ if (!string->IsSymbol() || !pattern->IsSymbol()) return Smi::FromInt(0);
+ uint32_t hash = string->Hash();
+ uint32_t index = ((hash & (kStringSplitCacheSize - 1)) &
+ ~(kArrayEntriesPerCacheEntry - 1));
+ if (cache->get(index + kStringOffset) == string &&
+ cache->get(index + kPatternOffset) == pattern) {
+ return cache->get(index + kArrayOffset);
+ }
+ index = ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
+ if (cache->get(index + kStringOffset) == string &&
+ cache->get(index + kPatternOffset) == pattern) {
+ return cache->get(index + kArrayOffset);
+ }
+ return Smi::FromInt(0);
+}
+
+
+void StringSplitCache::Enter(Heap* heap,
+ FixedArray* cache,
+ String* string,
+ String* pattern,
+ FixedArray* array) {
+ if (!string->IsSymbol() || !pattern->IsSymbol()) return;
+ uint32_t hash = string->Hash();
+ uint32_t index = ((hash & (kStringSplitCacheSize - 1)) &
+ ~(kArrayEntriesPerCacheEntry - 1));
+ if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
+ cache->set(index + kStringOffset, string);
+ cache->set(index + kPatternOffset, pattern);
+ cache->set(index + kArrayOffset, array);
+ } else {
+ uint32_t index2 =
+ ((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
+ if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
+ cache->set(index2 + kStringOffset, string);
+ cache->set(index2 + kPatternOffset, pattern);
+ cache->set(index2 + kArrayOffset, array);
+ } else {
+ cache->set(index2 + kStringOffset, Smi::FromInt(0));
+ cache->set(index2 + kPatternOffset, Smi::FromInt(0));
+ cache->set(index2 + kArrayOffset, Smi::FromInt(0));
+ cache->set(index + kStringOffset, string);
+ cache->set(index + kPatternOffset, pattern);
+ cache->set(index + kArrayOffset, array);
+ }
+ }
+ if (array->length() < 100) { // Limit how many new symbols we want to make.
+ for (int i = 0; i < array->length(); i++) {
+ String* str = String::cast(array->get(i));
+ Object* symbol;
+ MaybeObject* maybe_symbol = heap->LookupSymbol(str);
+ if (maybe_symbol->ToObject(&symbol)) {
+ array->set(i, symbol);
+ }
+ }
+ }
+ array->set_map(heap->fixed_cow_array_map());
+}
+
+
+void StringSplitCache::Clear(FixedArray* cache) {
+ for (int i = 0; i < kStringSplitCacheSize; i++) {
+ cache->set(i, Smi::FromInt(0));
+ }
+}
+
+
MaybeObject* Heap::InitializeNumberStringCache() {
// Compute the size of the number string cache based on the max heap size.
// max_semispace_size_ == 512 KB => number_string_cache_size = 32.
@@ -3339,11 +3415,36 @@
map->set_prototype(prototype);
// Allocate the proxy object.
- Object* result;
+ JSProxy* result;
MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- JSProxy::cast(result)->set_handler(handler);
- JSProxy::cast(result)->set_padding(Smi::FromInt(0));
+ if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
+ result->InitializeBody(map->instance_size(), Smi::FromInt(0));
+ result->set_handler(handler);
+ return result;
+}
+
+
+MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
+ Object* call_trap,
+ Object* construct_trap,
+ Object* prototype) {
+ // Allocate map.
+ // TODO(rossberg): Once we optimize proxies, think about a scheme to share
+ // maps. Will probably depend on the identity of the handler object, too.
+ Map* map;
+ MaybeObject* maybe_map_obj =
+ AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
+ if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
+ map->set_prototype(prototype);
+
+ // Allocate the proxy object.
+ JSFunctionProxy* result;
+ MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
+ if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
+ result->InitializeBody(map->instance_size(), Smi::FromInt(0));
+ result->set_handler(handler);
+ result->set_call_trap(call_trap);
+ result->set_construct_trap(construct_trap);
return result;
}
@@ -3488,16 +3589,19 @@
}
-MaybeObject* Heap::ReinitializeJSProxyAsJSObject(JSProxy* object) {
+MaybeObject* Heap::ReinitializeJSReceiver(
+ JSReceiver* object, InstanceType type, int size) {
+ ASSERT(type >= FIRST_JS_RECEIVER_TYPE);
+
// Allocate fresh map.
// TODO(rossberg): Once we optimize proxies, cache these maps.
Map* map;
- MaybeObject* maybe_map_obj =
- AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ MaybeObject* maybe_map_obj = AllocateMap(type, size);
if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
- // Check that the receiver has the same size as a fresh object.
- ASSERT(map->instance_size() == object->map()->instance_size());
+ // Check that the receiver has at least the size of the fresh object.
+ int size_difference = object->map()->instance_size() - map->instance_size();
+ ASSERT(size_difference >= 0);
map->set_prototype(object->map()->prototype());
@@ -3514,6 +3618,28 @@
// Reinitialize the object from the constructor map.
InitializeJSObjectFromMap(JSObject::cast(object),
FixedArray::cast(properties), map);
+
+ // Functions require some minimal initialization.
+ if (type == JS_FUNCTION_TYPE) {
+ String* name;
+ MaybeObject* maybe_name = LookupAsciiSymbol("<freezing call trap>");
+ if (!maybe_name->To<String>(&name)) return maybe_name;
+ SharedFunctionInfo* shared;
+ MaybeObject* maybe_shared = AllocateSharedFunctionInfo(name);
+ if (!maybe_shared->To<SharedFunctionInfo>(&shared)) return maybe_shared;
+ JSFunction* func;
+ MaybeObject* maybe_func =
+ InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
+ if (!maybe_func->To<JSFunction>(&func)) return maybe_func;
+ func->set_context(isolate()->context()->global_context());
+ }
+
+ // Put in filler if the new object is smaller than the old.
+ if (size_difference > 0) {
+ CreateFillerObjectAt(
+ object->address() + map->instance_size(), size_difference);
+ }
+
return object;
}
@@ -3546,6 +3672,9 @@
MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string,
PretenureFlag pretenure) {
+ if (string.length() == 1) {
+ return Heap::LookupSingleCharacterStringFromCode(string[0]);
+ }
Object* result;
{ MaybeObject* maybe_result =
AllocateRawAsciiString(string.length(), pretenure);
diff --git a/src/heap.h b/src/heap.h
index 0f69fab..d81ff6c 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -77,6 +77,7 @@
V(Object, instanceof_cache_map, InstanceofCacheMap) \
V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
+ V(FixedArray, string_split_cache, StringSplitCache) \
V(Object, termination_exception, TerminationException) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \
@@ -225,8 +226,7 @@
V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \
V(dot_symbol, ".") \
- V(anonymous_function_symbol, "(anonymous function)") \
- V(block_scope_symbol, ".block")
+ V(anonymous_function_symbol, "(anonymous function)")
// Forward declarations.
class GCTracer;
@@ -440,17 +440,25 @@
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateFunctionPrototype(JSFunction* function);
- // Allocates a Harmony Proxy.
+ // Allocates a Harmony proxy or function proxy.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateJSProxy(Object* handler,
Object* prototype);
- // Reinitialize a JSProxy into an (empty) JSObject. The receiver
- // must have the same size as an empty object. The object is reinitialized
- // and behaves as an object that has been freshly allocated.
- MUST_USE_RESULT MaybeObject* ReinitializeJSProxyAsJSObject(JSProxy* object);
+ MUST_USE_RESULT MaybeObject* AllocateJSFunctionProxy(Object* handler,
+ Object* call_trap,
+ Object* construct_trap,
+ Object* prototype);
+
+ // Reinitialize a JSReceiver into an (empty) JS object of respective type and
+ // size, but keeping the original prototype. The receiver must have at least
+ // the size of the new object. The object is reinitialized and behaves as an
+ // object that has been freshly allocated.
+ MUST_USE_RESULT MaybeObject* ReinitializeJSReceiver(JSReceiver* object,
+ InstanceType type,
+ int size);
// Reinitialize an JSGlobalProxy based on a constructor. The object
// must have the same size as objects allocated using the
@@ -2177,6 +2185,27 @@
};
+class StringSplitCache {
+ public:
+ static Object* Lookup(FixedArray* cache, String* string, String* pattern);
+ static void Enter(Heap* heap,
+ FixedArray* cache,
+ String* string,
+ String* pattern,
+ FixedArray* array);
+ static void Clear(FixedArray* cache);
+ static const int kStringSplitCacheSize = 0x100;
+
+ private:
+ static const int kArrayEntriesPerCacheEntry = 4;
+ static const int kStringOffset = 0;
+ static const int kPatternOffset = 1;
+ static const int kArrayOffset = 2;
+
+ static MaybeObject* WrapFixedArrayInJSArray(Object* fixed_array);
+};
+
+
class TranscendentalCache {
public:
enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches};
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index d3cc8a6..5630ce3 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -425,7 +425,7 @@
void HValue::PrintChangesTo(StringStream* stream) {
- int changes_flags = (flags() & HValue::ChangesFlagsMask());
+ int changes_flags = ChangesFlags();
if (changes_flags == 0) return;
stream->Add(" changes[");
if (changes_flags == AllSideEffects()) {
@@ -512,9 +512,7 @@
void HInstruction::PrintMnemonicTo(StringStream* stream) {
- stream->Add("%s", Mnemonic());
- if (HasSideEffects()) stream->Add("*");
- stream->Add(" ");
+ stream->Add("%s ", Mnemonic());
}
@@ -791,6 +789,13 @@
}
+void HJSArrayLength::PrintDataTo(StringStream* stream) {
+ value()->PrintNameTo(stream);
+ stream->Add(" ");
+ typecheck()->PrintNameTo(stream);
+}
+
+
HValue* HCheckInstanceType::Canonicalize() {
if (check_ == IS_STRING &&
!value()->type().IsUninitialized() &&
@@ -1020,11 +1025,14 @@
value->PrintNameTo(stream);
stream->Add(" ");
}
- stream->Add(" uses%d_%di_%dd_%dt]",
+ stream->Add(" uses%d_%di_%dd_%dt",
UseCount(),
int32_non_phi_uses() + int32_indirect_uses(),
double_non_phi_uses() + double_indirect_uses(),
tagged_non_phi_uses() + tagged_indirect_uses());
+ stream->Add("%s%s]",
+ is_live() ? "_live" : "",
+ IsConvertibleToInteger() ? "" : "_ncti");
}
@@ -1125,7 +1133,7 @@
void HEnterInlined::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name = function()->debug_name()->ToCString();
+ SmartArrayPointer<char> name = function()->debug_name()->ToCString();
stream->Add("%s, id=%d", *name, function()->id());
}
@@ -1299,6 +1307,12 @@
left()->PrintNameTo(stream);
stream->Add(" ");
right()->PrintNameTo(stream);
+ HControlInstruction::PrintDataTo(stream);
+}
+
+
+void HGoto::PrintDataTo(StringStream* stream) {
+ stream->Add("B%d", SuccessorAt(0)->block_id());
}
@@ -1446,37 +1460,37 @@
external_pointer()->PrintNameTo(stream);
stream->Add(".");
switch (elements_kind()) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
stream->Add("byte");
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
stream->Add("u_byte");
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
stream->Add("short");
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
stream->Add("u_short");
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
stream->Add("int");
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
stream->Add("u_int");
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
stream->Add("float");
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
stream->Add("double");
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
stream->Add("pixel");
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -1541,37 +1555,37 @@
external_pointer()->PrintNameTo(stream);
stream->Add(".");
switch (elements_kind()) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
stream->Add("byte");
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
stream->Add("u_byte");
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
stream->Add("short");
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
stream->Add("u_short");
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
stream->Add("int");
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
stream->Add("u_int");
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
stream->Add("float");
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
stream->Add("double");
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
stream->Add("pixel");
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 76007d7..1bc28ba 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -513,19 +513,6 @@
static const int kChangesToDependsFlagsLeftShift = 1;
- static int ChangesFlagsMask() {
- int result = 0;
- // Create changes mask.
-#define DECLARE_DO(type) result |= (1 << kChanges##type);
- GVN_FLAG_LIST(DECLARE_DO)
-#undef DECLARE_DO
- return result;
- }
-
- static int DependsFlagsMask() {
- return ConvertChangesToDependsFlags(ChangesFlagsMask());
- }
-
static int ConvertChangesToDependsFlags(int flags) {
return flags << kChangesToDependsFlagsLeftShift;
}
@@ -629,6 +616,8 @@
void ClearAllSideEffects() { flags_ &= ~AllSideEffects(); }
bool HasSideEffects() const { return (flags_ & AllSideEffects()) != 0; }
+ int ChangesFlags() const { return flags_ & ChangesFlagsMask(); }
+
Range* range() const { return range_; }
bool HasRange() const { return range_ != NULL; }
void AddNewRange(Range* r);
@@ -693,6 +682,15 @@
}
private:
+ static int ChangesFlagsMask() {
+ int result = 0;
+ // Create changes mask.
+#define ADD_FLAG(type) result |= (1 << kChanges##type);
+ GVN_FLAG_LIST(ADD_FLAG)
+#undef ADD_FLAG
+ return result;
+ }
+
// A flag mask to mark an instruction as having arbitrary side effects.
static int AllSideEffects() {
return ChangesFlagsMask() & ~(1 << kChangesOsrEntries);
@@ -917,6 +915,8 @@
return Representation::None();
}
+ virtual void PrintDataTo(StringStream* stream);
+
DECLARE_CONCRETE_INSTRUCTION(Goto)
};
@@ -1696,7 +1696,10 @@
return Representation::Tagged();
}
+ virtual void PrintDataTo(StringStream* stream);
+
HValue* value() { return OperandAt(0); }
+ HValue* typecheck() { return OperandAt(1); }
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)
@@ -2208,6 +2211,13 @@
is_convertible_to_integer_ = b;
}
+ bool AllOperandsConvertibleToInteger() {
+ for (int i = 0; i < OperandCount(); ++i) {
+ if (!OperandAt(i)->IsConvertibleToInteger()) return false;
+ }
+ return true;
+ }
+
protected:
virtual void DeleteFromGraph();
virtual void InternalSetOperandAt(int index, HValue* value) {
@@ -3554,12 +3564,12 @@
public:
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
- JSObject::ElementsKind elements_kind)
+ ElementsKind elements_kind)
: elements_kind_(elements_kind) {
SetOperandAt(0, external_elements);
SetOperandAt(1, key);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
set_representation(Representation::Double());
} else {
set_representation(Representation::Integer32());
@@ -3582,7 +3592,7 @@
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
- JSObject::ElementsKind elements_kind() const { return elements_kind_; }
+ ElementsKind elements_kind() const { return elements_kind_; }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement)
@@ -3595,7 +3605,7 @@
}
private:
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
};
@@ -3775,7 +3785,7 @@
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
HValue* key,
HValue* val,
- JSObject::ElementsKind elements_kind)
+ ElementsKind elements_kind)
: elements_kind_(elements_kind) {
SetFlag(kChangesSpecializedArrayElements);
SetOperandAt(0, external_elements);
@@ -3790,8 +3800,8 @@
return Representation::External();
} else {
bool float_or_double_elements =
- elements_kind() == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind() == JSObject::EXTERNAL_DOUBLE_ELEMENTS;
+ elements_kind() == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind() == EXTERNAL_DOUBLE_ELEMENTS;
if (index == 2 && float_or_double_elements) {
return Representation::Double();
} else {
@@ -3803,12 +3813,12 @@
HValue* external_pointer() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
- JSObject::ElementsKind elements_kind() const { return elements_kind_; }
+ ElementsKind elements_kind() const { return elements_kind_; }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement)
private:
- JSObject::ElementsKind elements_kind_;
+ ElementsKind elements_kind_;
};
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 5772141..c625fba 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -220,6 +220,17 @@
}
+int HBasicBlock::LoopNestingDepth() const {
+ const HBasicBlock* current = this;
+ int result = (current->IsLoopHeader()) ? 1 : 0;
+ while (current->parent_loop_header() != NULL) {
+ current = current->parent_loop_header();
+ result++;
+ }
+ return result;
+}
+
+
void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) {
ASSERT(IsLoopHeader());
@@ -638,8 +649,7 @@
PrintF("Crankshaft Compiler - ");
}
CodeGenerator::MakeCodePrologue(info);
- Code::Flags flags =
- Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP);
+ Code::Flags flags = Code::ComputeFlags(Code::OPTIMIZED_FUNCTION);
Handle<Code> code =
CodeGenerator::MakeCodeEpilogue(&assembler, flags, info);
generator.FinishCode(code);
@@ -840,7 +850,7 @@
}
-bool HGraph::CheckArgumentsPhiUses() {
+bool HGraph::CheckPhis() {
int block_count = blocks_.length();
for (int i = 0; i < block_count; ++i) {
for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
@@ -853,11 +863,13 @@
}
-bool HGraph::CheckConstPhiUses() {
+bool HGraph::CollectPhis() {
int block_count = blocks_.length();
+ phi_list_ = new ZoneList<HPhi*>(block_count);
for (int i = 0; i < block_count; ++i) {
for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
HPhi* phi = blocks_[i]->phis()->at(j);
+ phi_list_->Add(phi);
// Check for the hole value (from an uninitialized const).
for (int k = 0; k < phi->OperandCount(); k++) {
if (phi->OperandAt(k) == GetConstantHole()) return false;
@@ -868,18 +880,6 @@
}
-void HGraph::CollectPhis() {
- int block_count = blocks_.length();
- phi_list_ = new ZoneList<HPhi*>(block_count);
- for (int i = 0; i < block_count; ++i) {
- for (int j = 0; j < blocks_[i]->phis()->length(); ++j) {
- HPhi* phi = blocks_[i]->phis()->at(j);
- phi_list_->Add(phi);
- }
- }
-}
-
-
void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
BitVector in_worklist(GetMaximumValueID());
for (int i = 0; i < worklist->length(); ++i) {
@@ -1392,7 +1392,7 @@
int id = block->block_id();
int side_effects = 0;
while (instr != NULL) {
- side_effects |= (instr->flags() & HValue::ChangesFlagsMask());
+ side_effects |= instr->ChangesFlags();
instr = instr->next();
}
block_side_effects_[id] |= side_effects;
@@ -1512,7 +1512,7 @@
HInstruction* instr = block->first();
while (instr != NULL) {
HInstruction* next = instr->next();
- int flags = (instr->flags() & HValue::ChangesFlagsMask());
+ int flags = instr->ChangesFlags();
if (flags != 0) {
ASSERT(!instr->CheckFlag(HValue::kUseGVN));
// Clear all instructions in the map that are affected by side effects.
@@ -1651,18 +1651,20 @@
int non_tagged_count = double_count + int32_count;
// If a non-loop phi has tagged uses, don't convert it to untagged.
- if (value->IsPhi() && !value->block()->IsLoopHeader()) {
- if (tagged_count > 0) return Representation::None();
+ if (value->IsPhi() && !value->block()->IsLoopHeader() && tagged_count > 0) {
+ return Representation::None();
}
- if (non_tagged_count >= tagged_count) {
- if (int32_count > 0) {
- if (!value->IsPhi() || value->IsConvertibleToInteger()) {
- return Representation::Integer32();
- }
- }
- if (double_count > 0) return Representation::Double();
+ // Prefer unboxing over boxing, the latter is more expensive.
+ if (tagged_count > non_tagged_count) Representation::None();
+
+ // Prefer Integer32 over Double, if possible.
+ if (int32_count > 0 && value->IsConvertibleToInteger()) {
+ return Representation::Integer32();
}
+
+ if (double_count > 0) return Representation::Double();
+
return Representation::None();
}
@@ -1688,7 +1690,9 @@
bool change = true;
while (change) {
change = false;
- for (int i = 0; i < phi_count; ++i) {
+ // We normally have far more "forward edges" than "backward edges",
+ // so we terminate faster when we walk backwards.
+ for (int i = phi_count - 1; i >= 0; --i) {
HPhi* phi = phi_list->at(i);
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
HValue* use = it.value();
@@ -1701,40 +1705,25 @@
}
}
- // (3) Sum up the non-phi use counts of all connected phis. Don't include
- // the non-phi uses of the phi itself.
+ // (3) Use the phi reachability information from step 2 to
+ // (a) sum up the non-phi use counts of all connected phis.
+ // (b) push information about values which can't be converted to integer
+ // without deoptimization through the phi use-def chains, avoiding
+ // unnecessary deoptimizations later.
for (int i = 0; i < phi_count; ++i) {
HPhi* phi = phi_list->at(i);
+ bool cti = phi->AllOperandsConvertibleToInteger();
for (BitVector::Iterator it(connected_phis.at(i));
!it.Done();
it.Advance()) {
int index = it.Current();
- if (index != i) {
- HPhi* it_use = phi_list->at(it.Current());
- phi->AddNonPhiUsesFrom(it_use);
- }
+ HPhi* it_use = phi_list->at(it.Current());
+ if (index != i) phi->AddNonPhiUsesFrom(it_use); // Don't count twice!
+ if (!cti) it_use->set_is_convertible_to_integer(false);
}
}
- // (4) Compute phis that definitely can't be converted to integer
- // without deoptimization and mark them to avoid unnecessary deoptimization.
- change = true;
- while (change) {
- change = false;
- for (int i = 0; i < phi_count; ++i) {
- HPhi* phi = phi_list->at(i);
- for (int j = 0; j < phi->OperandCount(); ++j) {
- if (phi->IsConvertibleToInteger() &&
- !phi->OperandAt(j)->IsConvertibleToInteger()) {
- phi->set_is_convertible_to_integer(false);
- change = true;
- break;
- }
- }
- }
- }
-
-
+ // Initialize work list
for (int i = 0; i < graph_->blocks()->length(); ++i) {
HBasicBlock* block = graph_->blocks()->at(i);
const ZoneList<HPhi*>* phis = block->phis();
@@ -1749,6 +1738,7 @@
}
}
+ // Do a fixed point iteration, trying to improve representations
while (!worklist_.is_empty()) {
HValue* current = worklist_.RemoveLast();
in_worklist_.Remove(current->id());
@@ -2214,7 +2204,8 @@
void HGraphBuilder::Bailout(const char* reason) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason);
}
SetStackOverflow();
@@ -2286,10 +2277,6 @@
return NULL;
}
SetupScope(scope);
- VisitDeclarations(scope->declarations());
- HValue* context = environment()->LookupContext();
- AddInstruction(
- new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
// Add an edge to the body entry. This is warty: the graph's start
// environment will be used by the Lithium translation as the initial
@@ -2311,6 +2298,19 @@
current_block()->Goto(body_entry);
body_entry->SetJoinId(AstNode::kFunctionEntryId);
set_current_block(body_entry);
+
+ // Handle implicit declaration of the function name in named function
+ // expressions before other declarations.
+ if (scope->is_function_scope() && scope->function() != NULL) {
+ HandleDeclaration(scope->function(), Variable::CONST, NULL);
+ }
+ VisitDeclarations(scope->declarations());
+ AddSimulate(AstNode::kDeclarationsId);
+
+ HValue* context = environment()->LookupContext();
+ AddInstruction(
+ new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
+
VisitStatements(info()->function()->body());
if (HasStackOverflow()) return NULL;
@@ -2324,17 +2324,16 @@
graph()->OrderBlocks();
graph()->AssignDominators();
graph()->PropagateDeoptimizingMark();
- if (!graph()->CheckConstPhiUses()) {
- Bailout("Unsupported phi use of const variable");
- return NULL;
- }
graph()->EliminateRedundantPhis();
- if (!graph()->CheckArgumentsPhiUses()) {
- Bailout("Unsupported phi use of arguments");
+ if (!graph()->CheckPhis()) {
+ Bailout("Unsupported phi use of arguments object");
return NULL;
}
if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis();
- graph()->CollectPhis();
+ if (!graph()->CollectPhis()) {
+ Bailout("Unsupported phi use of uninitialized constant");
+ return NULL;
+ }
HInferRepresentation rep(graph());
rep.Analyze();
@@ -2465,14 +2464,6 @@
graph()->SetArgumentsObject(object);
environment()->Bind(scope->arguments(), object);
}
- // Handle implicit declaration of the function name in named function
- // expressions before other declarations.
- if (scope->is_function_scope() && scope->function() != NULL) {
- if (!scope->function()->IsStackAllocated()) {
- return Bailout("unsupported declaration");
- }
- environment()->Bind(scope->function(), graph()->GetConstantHole());
- }
}
@@ -2665,14 +2656,6 @@
}
-void HGraphBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
- ASSERT(!HasStackOverflow());
- ASSERT(current_block() != NULL);
- ASSERT(current_block()->HasPredecessor());
- return Bailout("ExitContextStatement");
-}
-
-
void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@@ -3141,56 +3124,63 @@
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- Variable* variable = expr->AsVariable();
- if (variable == NULL) {
- return Bailout("reference to rewritten variable");
- } else if (variable->mode() == Variable::LET) {
+ Variable* variable = expr->var();
+ if (variable->mode() == Variable::LET) {
return Bailout("reference to let variable");
- } else if (variable->IsStackAllocated()) {
- HValue* value = environment()->Lookup(variable);
- if (variable->mode() == Variable::CONST &&
- value == graph()->GetConstantHole()) {
- return Bailout("reference to uninitialized const variable");
- }
- return ast_context()->ReturnValue(value);
- } else if (variable->IsContextSlot()) {
- if (variable->mode() == Variable::CONST) {
- return Bailout("reference to const context slot");
- }
- HValue* context = BuildContextChainWalk(variable);
- int index = variable->AsSlot()->index();
- HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index);
- return ast_context()->ReturnInstruction(instr, expr->id());
- } else if (variable->is_global()) {
- LookupResult lookup;
- GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false);
+ }
+ switch (variable->location()) {
+ case Variable::UNALLOCATED: {
+ LookupResult lookup;
+ GlobalPropertyAccess type =
+ LookupGlobalProperty(variable, &lookup, false);
- if (type == kUseCell &&
- info()->global_object()->IsAccessCheckNeeded()) {
- type = kUseGeneric;
+ if (type == kUseCell &&
+ info()->global_object()->IsAccessCheckNeeded()) {
+ type = kUseGeneric;
+ }
+
+ if (type == kUseCell) {
+ Handle<GlobalObject> global(info()->global_object());
+ Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
+ bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
+ HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole);
+ return ast_context()->ReturnInstruction(instr, expr->id());
+ } else {
+ HValue* context = environment()->LookupContext();
+ HGlobalObject* global_object = new(zone()) HGlobalObject(context);
+ AddInstruction(global_object);
+ HLoadGlobalGeneric* instr =
+ new(zone()) HLoadGlobalGeneric(context,
+ global_object,
+ variable->name(),
+ ast_context()->is_for_typeof());
+ instr->set_position(expr->position());
+ return ast_context()->ReturnInstruction(instr, expr->id());
+ }
}
- if (type == kUseCell) {
- Handle<GlobalObject> global(info()->global_object());
- Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
- bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
- HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole);
- return ast_context()->ReturnInstruction(instr, expr->id());
- } else {
- HValue* context = environment()->LookupContext();
- HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- AddInstruction(global_object);
- HLoadGlobalGeneric* instr =
- new(zone()) HLoadGlobalGeneric(context,
- global_object,
- variable->name(),
- ast_context()->is_for_typeof());
- instr->set_position(expr->position());
- ASSERT(instr->HasSideEffects());
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ HValue* value = environment()->Lookup(variable);
+ if (variable->mode() == Variable::CONST &&
+ value == graph()->GetConstantHole()) {
+ return Bailout("reference to uninitialized const variable");
+ }
+ return ast_context()->ReturnValue(value);
+ }
+
+ case Variable::CONTEXT: {
+ if (variable->mode() == Variable::CONST) {
+ return Bailout("reference to const context slot");
+ }
+ HValue* context = BuildContextChainWalk(variable);
+ HLoadContextSlot* instr =
+ new(zone()) HLoadContextSlot(context, variable->index());
return ast_context()->ReturnInstruction(instr, expr->id());
}
- } else {
- return Bailout("reference to a variable which requires dynamic lookup");
+
+ case Variable::LOOKUP:
+ return Bailout("reference to a variable which requires dynamic lookup");
}
}
@@ -3602,52 +3592,61 @@
void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
Expression* target = expr->target();
VariableProxy* proxy = target->AsVariableProxy();
- Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty();
- ASSERT(var == NULL || prop == NULL);
+ ASSERT(proxy == NULL || prop == NULL);
// We have a second position recorded in the FullCodeGenerator to have
// type feedback for the binary operation.
BinaryOperation* operation = expr->binary_operation();
- if (var != NULL) {
- if (var->mode() == Variable::CONST ||
- var->mode() == Variable::LET) {
+ if (proxy != NULL) {
+ Variable* var = proxy->var();
+ if (var->mode() == Variable::CONST || var->mode() == Variable::LET) {
return Bailout("unsupported let or const compound assignment");
}
CHECK_ALIVE(VisitForValue(operation));
- if (var->is_global()) {
- HandleGlobalVariableAssignment(var,
- Top(),
- expr->position(),
- expr->AssignmentId());
- } else if (var->IsStackAllocated()) {
- Bind(var, Top());
- } else if (var->IsContextSlot()) {
- // Bail out if we try to mutate a parameter value in a function using
- // the arguments object. We do not (yet) correctly handle the
- // arguments property of the function.
- if (info()->scope()->arguments() != NULL) {
- // Parameters will rewrite to context slots. We have no direct way
- // to detect that the variable is a parameter.
- int count = info()->scope()->num_parameters();
- for (int i = 0; i < count; ++i) {
- if (var == info()->scope()->parameter(i)) {
- Bailout("assignment to parameter, function uses arguments object");
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ HandleGlobalVariableAssignment(var,
+ Top(),
+ expr->position(),
+ expr->AssignmentId());
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ Bind(var, Top());
+ break;
+
+ case Variable::CONTEXT: {
+ // Bail out if we try to mutate a parameter value in a function
+ // using the arguments object. We do not (yet) correctly handle the
+ // arguments property of the function.
+ if (info()->scope()->arguments() != NULL) {
+ // Parameters will be allocated to context slots. We have no
+ // direct way to detect that the variable is a parameter so we do
+ // a linear search of the parameter variables.
+ int count = info()->scope()->num_parameters();
+ for (int i = 0; i < count; ++i) {
+ if (var == info()->scope()->parameter(i)) {
+ Bailout(
+ "assignment to parameter, function uses arguments object");
+ }
}
}
+
+ HValue* context = BuildContextChainWalk(var);
+ HStoreContextSlot* instr =
+ new(zone()) HStoreContextSlot(context, var->index(), Top());
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ break;
}
- HValue* context = BuildContextChainWalk(var);
- int index = var->AsSlot()->index();
- HStoreContextSlot* instr =
- new(zone()) HStoreContextSlot(context, index, Top());
- AddInstruction(instr);
- if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
- } else {
- return Bailout("compound assignment to lookup slot");
+ case Variable::LOOKUP:
+ return Bailout("compound assignment to lookup slot");
}
return ast_context()->ReturnValue(Pop());
@@ -3735,16 +3734,18 @@
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
VariableProxy* proxy = expr->target()->AsVariableProxy();
- Variable* var = proxy->AsVariable();
Property* prop = expr->target()->AsProperty();
- ASSERT(var == NULL || prop == NULL);
+ ASSERT(proxy == NULL || prop == NULL);
if (expr->is_compound()) {
HandleCompoundAssignment(expr);
return;
}
- if (var != NULL) {
+ if (prop != NULL) {
+ HandlePropertyAssignment(expr);
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
if (var->mode() == Variable::CONST) {
if (expr->op() != Token::INIT_CONST) {
return Bailout("non-initializer assignment to const");
@@ -3763,54 +3764,54 @@
if (proxy->IsArguments()) return Bailout("assignment to arguments");
// Handle the assignment.
- if (var->IsStackAllocated()) {
- // We do not allow the arguments object to occur in a context where it
- // may escape, but assignments to stack-allocated locals are
- // permitted.
- CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
- HValue* value = Pop();
- Bind(var, value);
- return ast_context()->ReturnValue(value);
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ CHECK_ALIVE(VisitForValue(expr->value()));
+ HandleGlobalVariableAssignment(var,
+ Top(),
+ expr->position(),
+ expr->AssignmentId());
+ return ast_context()->ReturnValue(Pop());
- } else if (var->IsContextSlot()) {
- ASSERT(var->mode() != Variable::CONST);
- // Bail out if we try to mutate a parameter value in a function using
- // the arguments object. We do not (yet) correctly handle the
- // arguments property of the function.
- if (info()->scope()->arguments() != NULL) {
- // Parameters will rewrite to context slots. We have no direct way
- // to detect that the variable is a parameter.
- int count = info()->scope()->num_parameters();
- for (int i = 0; i < count; ++i) {
- if (var == info()->scope()->parameter(i)) {
- Bailout("assignment to parameter, function uses arguments object");
- }
- }
+ case Variable::PARAMETER:
+ case Variable::LOCAL: {
+ // We do not allow the arguments object to occur in a context where it
+ // may escape, but assignments to stack-allocated locals are
+ // permitted.
+ CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED));
+ HValue* value = Pop();
+ Bind(var, value);
+ return ast_context()->ReturnValue(value);
}
- CHECK_ALIVE(VisitForValue(expr->value()));
- HValue* context = BuildContextChainWalk(var);
- int index = var->AsSlot()->index();
- HStoreContextSlot* instr =
- new(zone()) HStoreContextSlot(context, index, Top());
- AddInstruction(instr);
- if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
- return ast_context()->ReturnValue(Pop());
+ case Variable::CONTEXT: {
+ ASSERT(var->mode() != Variable::CONST);
+ // Bail out if we try to mutate a parameter value in a function using
+ // the arguments object. We do not (yet) correctly handle the
+ // arguments property of the function.
+ if (info()->scope()->arguments() != NULL) {
+ // Parameters will rewrite to context slots. We have no direct way
+ // to detect that the variable is a parameter.
+ int count = info()->scope()->num_parameters();
+ for (int i = 0; i < count; ++i) {
+ if (var == info()->scope()->parameter(i)) {
+ return Bailout("assignment to parameter in arguments object");
+ }
+ }
+ }
- } else if (var->is_global()) {
- CHECK_ALIVE(VisitForValue(expr->value()));
- HandleGlobalVariableAssignment(var,
- Top(),
- expr->position(),
- expr->AssignmentId());
- return ast_context()->ReturnValue(Pop());
+ CHECK_ALIVE(VisitForValue(expr->value()));
+ HValue* context = BuildContextChainWalk(var);
+ HStoreContextSlot* instr =
+ new(zone()) HStoreContextSlot(context, var->index(), Top());
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ return ast_context()->ReturnValue(Pop());
+ }
- } else {
- return Bailout("assignment to LOOKUP or const CONTEXT variable");
+ case Variable::LOOKUP:
+ return Bailout("assignment to LOOKUP variable");
}
-
- } else if (prop != NULL) {
- HandlePropertyAssignment(expr);
} else {
return Bailout("invalid left-hand side in assignment");
}
@@ -3905,35 +3906,35 @@
HValue* external_elements,
HValue* checked_key,
HValue* val,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
bool is_store) {
if (is_store) {
ASSERT(val != NULL);
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
HClampToUint8* clamp = new(zone()) HClampToUint8(val);
AddInstruction(clamp);
val = clamp;
break;
}
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
HToInt32* floor_val = new(zone()) HToInt32(val);
AddInstruction(floor_val);
val = floor_val;
break;
}
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -4017,7 +4018,7 @@
SmallMapList* maps = prop->GetReceiverTypes();
bool todo_external_array = false;
- static const int kNumElementTypes = JSObject::kElementsKindCount;
+ static const int kNumElementTypes = kElementsKindCount;
bool type_todo[kNumElementTypes];
for (int i = 0; i < kNumElementTypes; ++i) {
type_todo[i] = false;
@@ -4027,7 +4028,7 @@
ASSERT(maps->at(i)->IsMap());
type_todo[maps->at(i)->elements_kind()] = true;
if (maps->at(i)->elements_kind()
- >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
+ >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) {
todo_external_array = true;
}
}
@@ -4042,16 +4043,16 @@
HInstruction* checked_key = NULL;
// FAST_ELEMENTS is assumed to be the first case.
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
- for (JSObject::ElementsKind elements_kind = JSObject::FAST_ELEMENTS;
- elements_kind <= JSObject::LAST_ELEMENTS_KIND;
- elements_kind = JSObject::ElementsKind(elements_kind + 1)) {
+ for (ElementsKind elements_kind = FAST_ELEMENTS;
+ elements_kind <= LAST_ELEMENTS_KIND;
+ elements_kind = ElementsKind(elements_kind + 1)) {
// After having handled FAST_ELEMENTS and DICTIONARY_ELEMENTS, we
// need to add some code that's executed for all external array cases.
- STATIC_ASSERT(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
- JSObject::LAST_ELEMENTS_KIND);
- if (elements_kind == JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
+ STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND ==
+ LAST_ELEMENTS_KIND);
+ if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND
&& todo_external_array) {
HInstruction* length =
AddInstruction(new(zone()) HFixedArrayBaseLength(elements));
@@ -4070,11 +4071,11 @@
set_current_block(if_true);
HInstruction* access;
- if (elements_kind == JSObject::FAST_ELEMENTS ||
- elements_kind == JSObject::FAST_DOUBLE_ELEMENTS) {
+ if (elements_kind == FAST_ELEMENTS ||
+ elements_kind == FAST_DOUBLE_ELEMENTS) {
bool fast_double_elements =
- elements_kind == JSObject::FAST_DOUBLE_ELEMENTS;
- if (is_store && elements_kind == JSObject::FAST_ELEMENTS) {
+ elements_kind == FAST_DOUBLE_ELEMENTS;
+ if (is_store && elements_kind == FAST_ELEMENTS) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map(),
elements_kind_branch));
@@ -4139,7 +4140,7 @@
new(zone()) HLoadKeyedFastElement(elements, checked_key));
}
}
- } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) {
+ } else if (elements_kind == DICTIONARY_ELEMENTS) {
if (is_store) {
access = AddInstruction(BuildStoreKeyedGeneric(object, key, val));
} else {
@@ -4434,8 +4435,10 @@
Handle<JSFunction> caller,
const char* reason) {
if (FLAG_trace_inlining) {
- SmartPointer<char> target_name = target->shared()->DebugName()->ToCString();
- SmartPointer<char> caller_name = caller->shared()->DebugName()->ToCString();
+ SmartArrayPointer<char> target_name =
+ target->shared()->DebugName()->ToCString();
+ SmartArrayPointer<char> caller_name =
+ caller->shared()->DebugName()->ToCString();
if (reason == NULL) {
PrintF("Inlined %s called from %s.\n", *target_name, *caller_name);
} else {
@@ -4922,10 +4925,12 @@
}
} else {
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
- bool global_call = (var != NULL) && var->is_global() && !var->is_this();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
+ // FIXME.
+ bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
if (global_call) {
+ Variable* var = proxy->var();
bool known_global_function = false;
// If there is a global property cell for the name at compile time and
// access check is not enabled we assume that the function will not change
@@ -5089,20 +5094,8 @@
void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
- if (prop == NULL && var == NULL) {
- // Result of deleting non-property, non-variable reference is true.
- // Evaluate the subexpression for side effects.
- CHECK_ALIVE(VisitForEffect(expr->expression()));
- return ast_context()->ReturnValue(graph()->GetConstantTrue());
- } else if (var != NULL &&
- !var->is_global() &&
- var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
- // Result of deleting non-global, non-dynamic variables is false.
- // The subexpression does not have side effects.
- return ast_context()->ReturnValue(graph()->GetConstantFalse());
- } else if (prop != NULL) {
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
+ if (prop != NULL) {
CHECK_ALIVE(VisitForValue(prop->obj()));
CHECK_ALIVE(VisitForValue(prop->key()));
HValue* key = Pop();
@@ -5110,10 +5103,26 @@
HValue* context = environment()->LookupContext();
HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
return ast_context()->ReturnInstruction(instr, expr->id());
- } else if (var->is_global()) {
- Bailout("delete with global variable");
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
+ if (var->IsUnallocated()) {
+ Bailout("delete with global variable");
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+ // Result of deleting non-global variables is false. 'this' is not
+ // really a variable, though we implement it as one. The
+ // subexpression does not have side effects.
+ HValue* value = var->is_this()
+ ? graph()->GetConstantTrue()
+ : graph()->GetConstantFalse();
+ return ast_context()->ReturnValue(value);
+ } else {
+ Bailout("delete with non-global variable");
+ }
} else {
- Bailout("delete with non-global variable");
+ // Result of deleting non-property, non-variable reference is true.
+ // Evaluate the subexpression for side effects.
+ CHECK_ALIVE(VisitForEffect(expr->expression()));
+ return ast_context()->ReturnValue(graph()->GetConstantTrue());
}
}
@@ -5260,9 +5269,8 @@
ASSERT(current_block()->HasPredecessor());
Expression* target = expr->expression();
VariableProxy* proxy = target->AsVariableProxy();
- Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty();
- if (var == NULL && prop == NULL) {
+ if (proxy == NULL && prop == NULL) {
return Bailout("invalid lhs in count operation");
}
@@ -5274,7 +5282,8 @@
HValue* input = NULL; // ToNumber(original_input).
HValue* after = NULL; // The result after incrementing or decrementing.
- if (var != NULL) {
+ if (proxy != NULL) {
+ Variable* var = proxy->var();
if (var->mode() == Variable::CONST) {
return Bailout("unsupported count operation with const");
}
@@ -5286,36 +5295,45 @@
input = returns_original_input ? Top() : Pop();
Push(after);
- if (var->is_global()) {
- HandleGlobalVariableAssignment(var,
- after,
- expr->position(),
- expr->AssignmentId());
- } else if (var->IsStackAllocated()) {
- Bind(var, after);
- } else if (var->IsContextSlot()) {
- // Bail out if we try to mutate a parameter value in a function using
- // the arguments object. We do not (yet) correctly handle the
- // arguments property of the function.
- if (info()->scope()->arguments() != NULL) {
- // Parameters will rewrite to context slots. We have no direct way
- // to detect that the variable is a parameter.
- int count = info()->scope()->num_parameters();
- for (int i = 0; i < count; ++i) {
- if (var == info()->scope()->parameter(i)) {
- Bailout("assignment to parameter, function uses arguments object");
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ HandleGlobalVariableAssignment(var,
+ after,
+ expr->position(),
+ expr->AssignmentId());
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ Bind(var, after);
+ break;
+
+ case Variable::CONTEXT: {
+ // Bail out if we try to mutate a parameter value in a function
+ // using the arguments object. We do not (yet) correctly handle the
+ // arguments property of the function.
+ if (info()->scope()->arguments() != NULL) {
+ // Parameters will rewrite to context slots. We have no direct
+ // way to detect that the variable is a parameter so we use a
+ // linear search of the parameter list.
+ int count = info()->scope()->num_parameters();
+ for (int i = 0; i < count; ++i) {
+ if (var == info()->scope()->parameter(i)) {
+ return Bailout("assignment to parameter in arguments object");
+ }
}
}
+
+ HValue* context = BuildContextChainWalk(var);
+ HStoreContextSlot* instr =
+ new(zone()) HStoreContextSlot(context, var->index(), after);
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ break;
}
- HValue* context = BuildContextChainWalk(var);
- int index = var->AsSlot()->index();
- HStoreContextSlot* instr =
- new(zone()) HStoreContextSlot(context, index, after);
- AddInstruction(instr);
- if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
- } else {
- return Bailout("lookup variable in count operation");
+ case Variable::LOOKUP:
+ return Bailout("lookup variable in count operation");
}
} else {
@@ -5727,12 +5745,12 @@
// residing in new space. If it is we assume that the function will stay the
// same.
Handle<JSFunction> target = Handle<JSFunction>::null();
- Variable* var = expr->right()->AsVariableProxy()->AsVariable();
- bool global_function = (var != NULL) && var->is_global() && !var->is_this();
+ VariableProxy* proxy = expr->right()->AsVariableProxy();
+ bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
if (global_function &&
info()->has_global_object() &&
!info()->global_object()->IsAccessCheckNeeded()) {
- Handle<String> name = var->name();
+ Handle<String> name = proxy->name();
Handle<GlobalObject> global(info()->global_object());
LookupResult lookup;
global->Lookup(*name, &lookup);
@@ -5831,17 +5849,42 @@
void HGraphBuilder::VisitDeclaration(Declaration* decl) {
- // We support only declarations that do not require code generation.
- Variable* var = decl->proxy()->var();
- if (!var->IsStackAllocated() ||
- decl->fun() != NULL ||
- decl->mode() == Variable::LET) {
- return Bailout("unsupported declaration");
- }
+ HandleDeclaration(decl->proxy(), decl->mode(), decl->fun());
+}
- if (decl->mode() == Variable::CONST) {
- ASSERT(var->IsStackAllocated());
- environment()->Bind(var, graph()->GetConstantHole());
+
+void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
+ Variable::Mode mode,
+ FunctionLiteral* function) {
+ if (mode == Variable::LET) return Bailout("unsupported let declaration");
+ Variable* var = proxy->var();
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ return Bailout("unsupported global declaration");
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT:
+ if (mode == Variable::CONST || function != NULL) {
+ HValue* value = NULL;
+ if (mode == Variable::CONST) {
+ value = graph()->GetConstantHole();
+ } else {
+ VisitForValue(function);
+ value = Pop();
+ }
+ if (var->IsContextSlot()) {
+ HValue* context = environment()->LookupContext();
+ HStoreContextSlot* store =
+ new HStoreContextSlot(context, var->index(), value);
+ AddInstruction(store);
+ if (store->HasSideEffects()) AddSimulate(proxy->id());
+ } else {
+ environment()->Bind(var, value);
+ }
+ }
+ break;
+ case Variable::LOOKUP:
+ return Bailout("unsupported lookup slot in declaration");
}
}
@@ -5874,7 +5917,9 @@
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasInstanceTypeAndBranch* result =
- new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE);
+ new(zone()) HHasInstanceTypeAndBranch(value,
+ JS_FUNCTION_TYPE,
+ JS_FUNCTION_PROXY_TYPE);
return ast_context()->ReturnControl(result, call->id());
}
@@ -6528,6 +6573,8 @@
PrintBlockProperty("dominator", current->dominator()->block_id());
}
+ PrintIntProperty("loop_depth", current->LoopNestingDepth());
+
if (chunk != NULL) {
int first_index = current->first_instruction_index();
int last_index = current->last_instruction_index();
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 1066d2c..03fbc73 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -102,6 +102,7 @@
void RemovePhi(HPhi* phi);
void AddInstruction(HInstruction* instr);
bool Dominates(HBasicBlock* other) const;
+ int LoopNestingDepth() const;
void SetInitialEnvironment(HEnvironment* env);
void ClearEnvironment() { last_environment_ = NULL; }
@@ -242,13 +243,11 @@
// Returns false if there are phi-uses of the arguments-object
// which are not supported by the optimizing compiler.
- bool CheckArgumentsPhiUses();
+ bool CheckPhis();
- // Returns false if there are phi-uses of an uninitialized const
- // which are not supported by the optimizing compiler.
- bool CheckConstPhiUses();
-
- void CollectPhis();
+ // Returns false if there are phi-uses of hole values comming
+ // from uninitialized consts.
+ bool CollectPhis();
Handle<Code> Compile(CompilationInfo* info);
@@ -457,12 +456,11 @@
// by 1 (receiver is parameter index -1 but environment index 0).
// Stack-allocated local indices are shifted by the number of parameters.
int IndexFor(Variable* variable) const {
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL && slot->IsStackAllocated());
- int shift = (slot->type() == Slot::PARAMETER)
+ ASSERT(variable->IsStackAllocated());
+ int shift = variable->IsParameter()
? 1
: parameter_count_ + specials_count_;
- return slot->index() + shift;
+ return variable->index() + shift;
}
Handle<JSFunction> closure_;
@@ -781,6 +779,10 @@
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
#undef INLINE_FUNCTION_GENERATOR_DECLARATION
+ void HandleDeclaration(VariableProxy* proxy,
+ Variable::Mode mode,
+ FunctionLiteral* function);
+
void VisitDelete(UnaryOperation* expr);
void VisitVoid(UnaryOperation* expr);
void VisitTypeof(UnaryOperation* expr);
@@ -853,7 +855,6 @@
TypeInfo info,
HValue* value,
Representation rep);
- void AssumeRepresentation(HValue* value, Representation rep);
static Representation ToRepresentation(TypeInfo info);
void SetupScope(Scope* scope);
@@ -935,7 +936,7 @@
HValue* external_elements,
HValue* checked_key,
HValue* val,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
bool is_store);
HInstruction* BuildMonomorphicElementAccess(HValue* object,
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index c186094..4698e3e 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -465,6 +465,7 @@
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
+
public:
explicit Scope(CpuFeature f) {
uint64_t mask = static_cast<uint64_t>(1) << f;
@@ -484,10 +485,12 @@
isolate_->set_enabled_cpu_features(old_enabled_);
}
}
+
private:
Isolate* isolate_;
uint64_t old_enabled_;
#else
+
public:
explicit Scope(CpuFeature f) {}
#endif
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index 845a073..310ea3d 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -590,16 +590,17 @@
// 2. Get the function to call (passed as receiver) from the stack, check
// if it is a function.
- Label non_function;
+ Label slow, non_function;
// 1 ~ return address.
__ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
__ JumpIfSmi(edi, &non_function);
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
- __ j(not_equal, &non_function);
+ __ j(not_equal, &slow);
// 3a. Patch the first argument if necessary when calling a function.
Label shift_arguments;
+ __ Set(edx, Immediate(0)); // indicate regular JS_FUNCTION
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
@@ -637,6 +638,7 @@
__ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ mov(ebx, eax);
+ __ Set(edx, Immediate(0)); // restore
__ pop(eax);
__ SmiUntag(eax);
@@ -661,14 +663,19 @@
__ jmp(&shift_arguments);
}
- // 3b. Patch the first argument when calling a non-function. The
+ // 3b. Check for function proxy.
+ __ bind(&slow);
+ __ Set(edx, Immediate(1)); // indicate function proxy
+ __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
+ __ j(equal, &shift_arguments);
+ __ bind(&non_function);
+ __ Set(edx, Immediate(2)); // indicate non-function
+
+ // 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
// receiver, so overwrite the first argument which will ultimately
// become the receiver.
- __ bind(&non_function);
__ mov(Operand(esp, eax, times_4, 0), edi);
- // Clear edi to indicate a non-function being called.
- __ Set(edi, Immediate(0));
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@@ -685,13 +692,26 @@
__ dec(eax); // One fewer argument (first argument is new receiver).
}
- // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
- { Label function;
- __ test(edi, Operand(edi));
- __ j(not_zero, &function);
+ // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+ // or a function proxy via CALL_FUNCTION_PROXY.
+ { Label function, non_proxy;
+ __ test(edx, Operand(edx));
+ __ j(zero, &function);
__ Set(ebx, Immediate(0));
- __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(ecx, CALL_AS_METHOD);
+ __ cmp(Operand(edx), Immediate(1));
+ __ j(not_equal, &non_proxy);
+
+ __ pop(edx); // return address
+ __ push(edi); // re-add proxy object as additional argument
+ __ push(edx);
+ __ inc(eax);
+ __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
+ __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ bind(&non_proxy);
+ __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
@@ -717,13 +737,17 @@
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+ static const int kArgumentsOffset = 2 * kPointerSize;
+ static const int kReceiverOffset = 3 * kPointerSize;
+ static const int kFunctionOffset = 4 * kPointerSize;
+
__ EnterInternalFrame();
- __ push(Operand(ebp, 4 * kPointerSize)); // push this
- __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
+ __ push(Operand(ebp, kFunctionOffset)); // push this
+ __ push(Operand(ebp, kArgumentsOffset)); // push arguments
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow. We are not trying need to catch
+ // Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
@@ -756,16 +780,21 @@
__ push(eax); // limit
__ push(Immediate(0)); // index
- // Change context eagerly to get the right global object if
- // necessary.
- __ mov(edi, Operand(ebp, 4 * kPointerSize));
+ // Get the receiver.
+ __ mov(ebx, Operand(ebp, kReceiverOffset));
+
+ // Check that the function is a JS function (otherwise it must be a proxy).
+ Label push_receiver;
+ __ mov(edi, Operand(ebp, kFunctionOffset));
+ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
+ __ j(not_equal, &push_receiver);
+
+ // Change context eagerly to get the right global object if necessary.
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Compute the receiver.
- Label call_to_object, use_global_receiver, push_receiver;
- __ mov(ebx, Operand(ebp, 3 * kPointerSize));
-
// Do not transform the receiver for strict mode functions.
+ Label call_to_object, use_global_receiver;
__ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
1 << SharedFunctionInfo::kStrictModeBitWithinByte);
@@ -814,7 +843,7 @@
__ mov(eax, Operand(ebp, kIndexOffset));
__ jmp(&entry);
__ bind(&loop);
- __ mov(edx, Operand(ebp, 2 * kPointerSize)); // load arguments
+ __ mov(edx, Operand(ebp, kArgumentsOffset)); // load arguments
// Use inline caching to speed up access to arguments.
Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
@@ -837,14 +866,30 @@
__ j(not_equal, &loop);
// Invoke the function.
+ Label call_proxy;
ParameterCount actual(eax);
__ SmiUntag(eax);
- __ mov(edi, Operand(ebp, 4 * kPointerSize));
+ __ mov(edi, Operand(ebp, kFunctionOffset));
+ __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
+ __ j(not_equal, &call_proxy);
__ InvokeFunction(edi, actual, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
__ LeaveInternalFrame();
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
+
+ // Invoke the function proxy.
+ __ bind(&call_proxy);
+ __ push(edi); // add function proxy as last argument
+ __ inc(eax);
+ __ Set(ebx, Immediate(0));
+ __ SetCallKind(ecx, CALL_AS_METHOD);
+ __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
+ __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ LeaveInternalFrame();
+ __ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 85e74b8..1009aaf 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -3551,7 +3551,7 @@
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
masm->isolate());
__ mov(edx,
Operand::StaticVariable(ExternalReference::the_hole_value_location(
@@ -4199,7 +4199,7 @@
void CallFunctionStub::Generate(MacroAssembler* masm) {
- Label slow;
+ Label slow, non_function;
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
@@ -4224,7 +4224,7 @@
__ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
// Check that the function really is a JavaScript function.
- __ JumpIfSmi(edi, &slow);
+ __ JumpIfSmi(edi, &non_function);
// Goto slow case if we do not have a function.
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(not_equal, &slow);
@@ -4251,15 +4251,32 @@
// Slow-case: Non-function called.
__ bind(&slow);
+ // Check for function proxy.
+ __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
+ __ j(not_equal, &non_function);
+ __ pop(ecx);
+ __ push(edi); // put proxy as additional argument under return address
+ __ push(ecx);
+ __ Set(eax, Immediate(argc_ + 1));
+ __ Set(ebx, Immediate(0));
+ __ SetCallKind(ecx, CALL_AS_FUNCTION);
+ __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
+ {
+ Handle<Code> adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ jmp(adaptor, RelocInfo::CODE_TARGET);
+ }
+
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
+ __ bind(&non_function);
__ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi);
__ Set(eax, Immediate(argc_));
__ Set(ebx, Immediate(0));
+ __ SetCallKind(ecx, CALL_AS_METHOD);
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
- __ SetCallKind(ecx, CALL_AS_METHOD);
__ jmp(adaptor, RelocInfo::CODE_TARGET);
}
@@ -4341,7 +4358,7 @@
__ j(zero, &failure_returned);
ExternalReference pending_exception_address(
- Isolate::k_pending_exception_address, masm->isolate());
+ Isolate::kPendingExceptionAddress, masm->isolate());
// Check that there is no pending exception, otherwise we
// should have returned some failure value.
@@ -4482,11 +4499,11 @@
__ push(ebx);
// Save copies of the top frame descriptor on the stack.
- ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, masm->isolate());
+ ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate());
__ push(Operand::StaticVariable(c_entry_fp));
// If this is the outermost JS call, set js_entry_sp value.
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address,
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
masm->isolate());
__ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
__ j(not_equal, ¬_outermost_js, Label::kNear);
@@ -4503,7 +4520,7 @@
// Caught exception: Store result (exception) in the pending
// exception field in the JSEnv and return a failure sentinel.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
masm->isolate());
__ mov(Operand::StaticVariable(pending_exception), eax);
__ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
@@ -4554,7 +4571,7 @@
// Restore the top frame descriptor from the stack.
__ pop(Operand::StaticVariable(ExternalReference(
- Isolate::k_c_entry_fp_address,
+ Isolate::kCEntryFPAddress,
masm->isolate())));
// Restore callee-saved registers (C calling conventions).
@@ -4907,7 +4924,8 @@
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ test(result_, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear);
@@ -5178,8 +5196,9 @@
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
__ and_(ecx, Operand(edi));
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
- __ test(ecx, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ test(ecx, Immediate(kStringEncodingMask));
__ j(zero, &non_ascii);
__ bind(&ascii_data);
// Allocate an acsii cons string.
@@ -5210,7 +5229,7 @@
__ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
__ j(equal, &ascii_data);
// Allocate a two byte cons string.
- __ AllocateConsString(ecx, edi, no_reg, &string_add_runtime);
+ __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime);
__ jmp(&allocated);
// Handle creating a flat result. First check that both strings are not
@@ -5236,12 +5255,13 @@
// ebx: length of resulting flat string as a smi
// edx: second string
Label non_ascii_string_add_flat_result;
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
+ __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
__ j(zero, &non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
+ __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
__ j(zero, &string_add_runtime);
// Both strings are ascii strings. As they are short they are both flat.
@@ -5281,7 +5301,7 @@
// edx: second string
__ bind(&non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
- __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag);
+ __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kStringEncodingMask);
__ j(not_zero, &string_add_runtime);
// Both strings are two byte strings. As they are short they are both
// flat.
@@ -5759,13 +5779,14 @@
// string's encoding is wrong because we always have to recheck encoding of
// the newly created string's parent anyways due to externalized strings.
Label two_byte_slice, set_slice_header;
- STATIC_ASSERT(kAsciiStringTag != 0);
- __ test(ebx, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ test(ebx, Immediate(kStringEncodingMask));
__ j(zero, &two_byte_slice, Label::kNear);
__ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime);
__ jmp(&set_slice_header, Label::kNear);
__ bind(&two_byte_slice);
- __ AllocateSlicedString(eax, ebx, no_reg, &runtime);
+ __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
__ bind(&set_slice_header);
__ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
__ SmiTag(ecx);
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index df2542e..ca6ce6e 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -41,7 +41,6 @@
namespace v8 {
namespace internal {
-
#define __ ACCESS_MASM(masm_)
@@ -192,14 +191,14 @@
// Copy parameters into context if necessary.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
@@ -241,7 +240,7 @@
ArgumentsAccessStub stub(type);
__ CallStub(&stub);
- Move(arguments->AsSlot(), eax, ebx, edx);
+ SetVar(arguments, eax, ebx, edx);
}
if (FLAG_trace) {
@@ -255,17 +254,19 @@
scope()->VisitIllegalRedeclaration(this);
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate());
@@ -371,27 +372,29 @@
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
- __ mov(result_register(), slot_operand);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ MemOperand operand = codegen()->VarOperand(var, result_register());
// Memory operands can be pushed directly.
- __ push(slot_operand);
+ __ push(operand);
codegen()->increment_stack_height();
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
// For simplicity we always test the accumulator register.
- codegen()->Move(result_register(), slot);
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -615,44 +618,54 @@
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return Operand(ebp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
}
- UNREACHABLE();
- return Operand(eax, 0);
+ return Operand(ebp, offset);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
- MemOperand location = EmitSlotSearch(source, destination);
- __ mov(destination, location);
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
+ }
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ MemOperand location = VarOperand(var, dest);
+ __ mov(dest, location);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
__ mov(location, src);
// Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- int offset = Context::SlotOffset(dst->index());
- ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi));
- __ RecordWrite(scratch1, offset, src, scratch2);
+ if (var->IsContextSlot()) {
+ int offset = Context::SlotOffset(var->index());
+ ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
+ __ RecordWrite(scratch0, offset, src, scratch1);
}
}
@@ -683,29 +696,33 @@
}
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ mov(Operand(ebp, SlotOffset(slot)), result_register());
+ __ mov(StackOperand(variable), result_register());
} else if (mode == Variable::CONST || mode == Variable::LET) {
- __ mov(Operand(ebp, SlotOffset(slot)),
+ Comment cmnt(masm_, "[ Declaration");
+ __ mov(StackOperand(variable),
Immediate(isolate()->factory()->the_hole_value()));
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -718,22 +735,27 @@
__ Check(not_equal, "Declaration in catch context.");
}
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ mov(ContextOperand(esi, slot->index()), result_register());
- int offset = Context::SlotOffset(slot->index());
+ __ mov(ContextOperand(esi, variable->index()), result_register());
+ int offset = Context::SlotOffset(variable->index());
__ mov(ebx, esi);
__ RecordWrite(ebx, offset, result_register(), ecx);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
- __ mov(ContextOperand(esi, slot->index()),
+ Comment cmnt(masm_, "[ Declaration");
+ __ mov(ContextOperand(esi, variable->index()),
Immediate(isolate()->factory()->the_hole_value()));
// No write barrier since the hole value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ push(esi);
__ push(Immediate(variable->name()));
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -750,7 +772,7 @@
__ push(Immediate(isolate()->factory()->the_hole_value()));
increment_stack_height();
} else {
- __ push(Immediate(Smi::FromInt(0))); // No initial value!
+ __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
increment_stack_height();
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
@@ -761,18 +783,15 @@
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(esi); // The context is the first argument.
__ push(Immediate(pairs));
- __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags())));
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1071,10 +1090,9 @@
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register context = esi;
Register temp = edx;
@@ -1123,7 +1141,7 @@
// All extension objects were empty and it is safe to use a global
// load IC call.
__ mov(eax, GlobalObjectOperand());
- __ mov(ecx, slot->var()->name());
+ __ mov(ecx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
@@ -1132,14 +1150,13 @@
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = esi;
Register temp = ebx;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1159,60 +1176,31 @@
// This function is used only for loads, not stores, so it's safe to
// return an esi-based operand (the write barrier cannot be allowed to
// destroy the esi register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ mov(eax,
- ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ cmp(eax, isolate()->factory()->the_hole_value());
- __ j(not_equal, done);
- __ mov(eax, isolate()->factory()->undefined_value());
- }
- __ jmp(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ mov(edx,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ SafeSet(eax, Immediate(key_literal->handle()));
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ jmp(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ cmp(eax, isolate()->factory()->the_hole_value());
+ __ j(not_equal, done);
+ __ mov(eax, isolate()->factory()->undefined_value());
}
+ __ jmp(done);
}
}
@@ -1222,66 +1210,60 @@
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
-
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in ecx and the global
- // object on the stack.
- __ mov(eax, GlobalObjectOperand());
- __ mov(ecx, var->name());
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(eax);
-
- } else if (slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ push(esi); // Context.
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
-
- context()->Plug(eax);
-
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, eax);
- __ mov(eax, slot_operand);
- __ cmp(eax, isolate()->factory()->the_hole_value());
- __ j(not_equal, &done, Label::kNear);
- __ mov(eax, isolate()->factory()->undefined_value());
- __ bind(&done);
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in ecx and the global
+ // object in eax.
+ __ mov(eax, GlobalObjectOperand());
+ __ mov(ecx, var->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(eax);
- } else if (var->mode() == Variable::LET) {
- // Let bindings may be the hole value if they have not been initialized.
- // Throw a type error in this case.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, eax);
- __ mov(eax, slot_operand);
- __ cmp(eax, isolate()->factory()->the_hole_value());
- __ j(not_equal, &done, Label::kNear);
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot()
+ ? "Context variable"
+ : "Stack variable");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ Label done;
+ GetVar(eax, var);
+ __ cmp(eax, isolate()->factory()->the_hole_value());
+ __ j(not_equal, &done, Label::kNear);
+ if (var->mode() == Variable::LET) {
+ __ push(Immediate(var->name()));
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ } else { // Variable::CONST
+ __ mov(eax, isolate()->factory()->undefined_value());
+ }
+ __ bind(&done);
+ context()->Plug(eax);
+ }
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup variable");
+ __ push(esi); // Context.
__ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
context()->Plug(eax);
- } else {
- context()->Plug(slot);
+ break;
}
}
}
@@ -1824,14 +1806,8 @@
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in eax, variable name in
- // ecx, and the global object on the stack.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ mov(ecx, var->name());
__ mov(edx, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode()
@@ -1840,117 +1816,79 @@
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- __ mov(edx, Operand(ebp, SlotOffset(slot)));
- __ cmp(edx, isolate()->factory()->the_hole_value());
- __ j(not_equal, &skip);
- __ mov(Operand(ebp, SlotOffset(slot)), eax);
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(eax);
- __ push(esi);
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ mov(edx, StackOperand(var));
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ j(not_equal, &skip);
+ __ mov(StackOperand(var), eax);
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(eax);
+ __ push(esi);
+ __ push(Immediate(var->name()));
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL: {
- Label assign;
- // Check for an initialized let binding.
- __ mov(edx, Operand(ebp, SlotOffset(slot)));
- __ cmp(edx, isolate()->factory()->the_hole_value());
- __ j(not_equal, &assign);
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ mov(Operand(ebp, SlotOffset(slot)), eax);
- break;
- }
-
- case Slot::CONTEXT: {
- // Let variables may be the hole value if they have not been
- // initialized. Throw a type error in this case.
- Label assign;
- MemOperand target = EmitSlotSearch(slot, ecx);
- // Check for an initialized let binding.
- __ mov(edx, target);
- __ cmp(edx, isolate()->factory()->the_hole_value());
- __ j(not_equal, &assign, Label::kNear);
- __ push(Immediate(var->name()));
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ mov(target, eax);
- // The value of the assignment is in eax. RecordWrite clobbers its
- // register arguments.
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(eax); // Value.
+ __ push(esi); // Context.
+ __ push(Immediate(var->name()));
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, ecx);
+ __ mov(edx, location);
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ j(not_equal, &assign, Label::kNear);
+ __ push(Immediate(var->name()));
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&assign);
+ __ mov(location, eax);
+ if (var->IsContextSlot()) {
__ mov(edx, eax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(ecx, offset, edx, ebx);
- break;
+ __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(eax); // Value.
- __ push(esi); // Context.
- __ push(Immediate(var->name()));
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
}
+
} else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ mov(Operand(ebp, SlotOffset(slot)), eax);
- break;
-
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, ecx);
- // Perform the assignment and issue the write barrier.
- __ mov(target, eax);
- // The value of the assignment is in eax. RecordWrite clobbers its
- // register arguments.
- __ mov(edx, eax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(ecx, offset, edx, ebx);
- break;
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, ecx);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ mov(edx, location);
+ __ cmp(edx, isolate()->factory()->the_hole_value());
+ __ Check(equal, "Let binding re-initialization.");
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(eax); // Value.
- __ push(esi); // Context.
- __ push(Immediate(var->name()));
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ // Perform the assignment.
+ __ mov(location, eax);
+ if (var->IsContextSlot()) {
+ __ mov(edx, eax);
+ __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
+ }
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(eax); // Value.
+ __ push(esi); // Context.
+ __ push(Immediate(var->name()));
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -2075,9 +2013,8 @@
}
// Record source position of the IC call.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2109,9 +2046,8 @@
}
// Record source position of the IC call.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
- arg_count, in_loop);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key.
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2133,8 +2069,7 @@
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2157,8 +2092,13 @@
// Push the receiver of the enclosing function.
__ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
- // Push the strict mode flag.
- __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ push(Immediate(Smi::FromInt(strict_mode)));
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
? Runtime::kResolvePossiblyDirectEvalNoLookup
@@ -2174,18 +2114,18 @@
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
- // resolve the function we need to call and the receiver of the
- // call. Then we call the resolved function using the given
- // arguments.
+ // resolve the function we need to call and the receiver of the call.
+ // Then we call the resolved function using the given arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
// Reserved receiver slot.
__ push(Immediate(isolate()->factory()->undefined_value()));
increment_stack_height();
@@ -2195,15 +2135,14 @@
}
// If we know that eval can only be shadowed by eval-introduced
- // variables we attempt to load the global eval function directly
- // in generated code. If we succeed, there is no need to perform a
+ // variables we attempt to load the global eval function directly in
+ // generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(eax);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2211,13 +2150,11 @@
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
+ // Push a copy of the function (found below the arguments) and
// resolve eval.
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in eax (function) and
// edx (receiver). Touch up the stack with the right values.
@@ -2226,83 +2163,74 @@
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
decrement_stack_height(arg_count + 1); // Function is left on the stack.
context()->DropAndPlug(1, eax);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
+
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
__ push(GlobalObjectOperand());
increment_stack_height();
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
-
{ PreservePositionScope scope(masm()->positions_recorder());
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ // Generate code for loading from variables potentially shadowed by
+ // eval-introduced variables.
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
-
__ bind(&slow);
- // Call the runtime to find the function to call (returned in eax)
- // and the object holding it (returned in edx).
+ // Call the runtime to find the function to call (returned in eax) and
+ // the object holding it (returned in edx).
__ push(context_register());
- __ push(Immediate(var->name()));
+ __ push(Immediate(proxy->name()));
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ push(eax); // Function.
- increment_stack_height();
__ push(edx); // Receiver.
- increment_stack_height();
+ increment_stack_height(2);
- // If fast case code has been generated, emit code to push the
- // function and receiver and have the slow path jump around this
- // code.
+ // If fast case code has been generated, emit code to push the function
+ // and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
- __ jmp(&call);
+ __ jmp(&call, Label::kNear);
__ bind(&done);
- // Push function. Stack height already incremented in slow case above.
+ // Push function. Stack height already incremented in slow case
+ // above.
__ push(eax);
- // The receiver is implicitly the global receiver. Indicate this
- // by passing the hole to the call function stub.
+ // The receiver is implicitly the global receiver. Indicate this by
+ // passing the hole to the call function stub.
__ push(Immediate(isolate()->factory()->the_hole_value()));
__ bind(&call);
}
- // The receiver is either the global receiver or an object found
- // by LoadContextSlot. That object could be the hole if the
- // receiver is implicitly the global object.
+ // The receiver is either the global receiver or an object found by
+ // LoadContextSlot. That object could be the hole if the receiver is
+ // implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
- } else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
- }
- } else {
+
+ } else if (property != NULL) {
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
+ } else {
+ EmitKeyedCallWithIC(expr, property->key());
+ }
+
+ } else {
+ // Call to an arbitrary expression not handled specially above.
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ mov(ebx, GlobalObjectOperand());
@@ -3650,10 +3578,9 @@
if (expr->is_jsruntime()) {
// Call the JS runtime function via a call IC.
__ Set(ecx, Immediate(expr->name()));
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
- Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(
- arg_count, in_loop, mode);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -3674,31 +3601,32 @@
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
decrement_stack_height(2);
context()->Plug(eax);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ push(GlobalObjectOperand());
__ push(Immediate(var->name()));
__ push(Immediate(Smi::FromInt(kNonStrictMode)));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(eax);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
- // Result of deleting non-global, non-dynamic variables is false.
- // The subexpression does not have side effects.
- context()->Plug(false);
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+ // Result of deleting non-global variables is false. 'this' is
+ // not really a variable, though we implement it as one. The
+ // subexpression does not have side effects.
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3995,7 +3923,7 @@
ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest());
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ mov(eax, GlobalObjectOperand());
__ mov(ecx, Immediate(proxy->name()));
@@ -4005,15 +3933,12 @@
__ call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(eax);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ push(esi);
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index 7d3ead2..9b5cc56 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -144,7 +144,7 @@
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
- Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
@@ -198,9 +198,9 @@
StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
Immediate(kTypeAndReadOnlyMask));
__ j(not_zero, miss_label);
@@ -832,7 +832,6 @@
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1237,9 +1236,7 @@
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx,
edx);
@@ -1339,10 +1336,8 @@
// -- esp[0] : return address
// -----------------------------------
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
no_reg);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 32e3074..4e3ea98 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -88,7 +88,8 @@
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LCodeGen in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -194,14 +195,14 @@
// Copy parameters into context if necessary.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved
// registers, so we have to use a third register to avoid
@@ -2219,11 +2220,11 @@
__ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Map::kElementsKindMask);
__ shr(temp, Map::kElementsKindShift);
- __ cmp(temp, JSObject::FAST_ELEMENTS);
+ __ cmp(temp, FAST_ELEMENTS);
__ j(equal, &ok, Label::kNear);
- __ cmp(temp, JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less, &fail, Label::kNear);
- __ cmp(temp, JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
+ __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
__ j(less_equal, &ok, Label::kNear);
__ bind(&fail);
__ Abort("Check for fast or external elements failed.");
@@ -2264,7 +2265,7 @@
// Load the result.
__ mov(result,
BuildFastArrayOperand(instr->elements(), instr->key(),
- JSObject::FAST_ELEMENTS,
+ FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value.
@@ -2284,14 +2285,14 @@
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(), instr->key(),
- JSObject::FAST_DOUBLE_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
offset);
__ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
}
Operand double_load_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movdbl(result, double_load_operand);
}
@@ -2300,7 +2301,7 @@
Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
@@ -2320,35 +2321,35 @@
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
__ cvtss2sd(result, result);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movdbl(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ movsx_b(result, operand);
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movzx_b(result, operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsx_w(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzx_w(result, operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ mov(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ mov(result, operand);
__ test(result, Operand(result));
// TODO(danno): we could be more clever here, perhaps having a special
@@ -2356,12 +2357,12 @@
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(negative, instr->environment());
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -2980,8 +2981,8 @@
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- Handle<Code> ic = isolate()->stub_cache()->
- ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
}
@@ -2993,7 +2994,7 @@
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(ecx, instr->name());
CallCode(ic, mode, instr);
}
@@ -3004,7 +3005,7 @@
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
- CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ Drop(1);
}
@@ -3017,7 +3018,7 @@
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(ecx, instr->name());
CallCode(ic, mode, instr);
}
@@ -3103,36 +3104,36 @@
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(operand, xmm0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movdbl(operand, ToDoubleRegister(instr->value()));
} else {
Register value = ToRegister(instr->value());
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ mov_b(operand, value);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(operand, value);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ mov(operand, value);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3175,7 +3176,6 @@
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
- Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
Label have_value;
__ ucomisd(value, value);
@@ -3187,7 +3187,7 @@
__ bind(&have_value);
Operand double_store_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movdbl(double_store_operand, value);
}
@@ -3269,7 +3269,8 @@
// Dispatch on the encoding: ASCII or two-byte.
Label ascii_string;
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ test(result, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear);
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index d26f245..6156327 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -224,7 +224,7 @@
int ToInteger32(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation.
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index f59ee07..3dc220d 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -315,13 +315,13 @@
void LCallNamed::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallGlobal::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
@@ -540,7 +540,8 @@
void LChunkBuilder::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LChunk building in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -706,9 +707,7 @@
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
- int argument_index_accumulator = 0;
- instr->set_environment(CreateEnvironment(hydrogen_env,
- &argument_index_accumulator));
+ instr->set_environment(CreateEnvironment(hydrogen_env));
return instr;
}
@@ -995,13 +994,10 @@
}
-LEnvironment* LChunkBuilder::CreateEnvironment(
- HEnvironment* hydrogen_env,
- int* argument_index_accumulator) {
+LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (hydrogen_env == NULL) return NULL;
- LEnvironment* outer =
- CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
+ LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
@@ -1011,6 +1007,7 @@
argument_count_,
value_count,
outer);
+ int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@@ -1019,7 +1016,7 @@
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
- op = new LArgument((*argument_index_accumulator)++);
+ op = new LArgument(argument_index++);
} else {
op = UseAny(value);
}
@@ -1906,15 +1903,15 @@
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Representation representation(instr->representation());
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
@@ -1924,7 +1921,7 @@
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
- return (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS)
+ return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS)
? AssignEnvironment(load_instr)
: load_instr;
}
@@ -1976,23 +1973,23 @@
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
LOperand* val = NULL;
- if (elements_kind == JSObject::EXTERNAL_BYTE_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// We need a byte register in this case for the value.
val = UseFixed(instr->value(), eax);
} else {
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 4b407a3..038049c 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -1184,7 +1184,7 @@
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -1699,7 +1699,7 @@
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -2259,8 +2259,7 @@
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
- LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
- int* argument_index_accumulator);
+ LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
void VisitInstruction(HInstruction* current);
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index dff174c..837112a 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -287,7 +287,7 @@
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
cmpb(FieldOperand(map, Map::kBitField2Offset),
Map::kMaximumBitField2FastElementValue);
j(above, fail, distance);
@@ -437,9 +437,9 @@
push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
// Save the frame pointer and the context in top.
- ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
isolate());
- ExternalReference context_address(Isolate::k_context_address,
+ ExternalReference context_address(Isolate::kContextAddress,
isolate());
mov(Operand::StaticVariable(c_entry_fp_address), ebp);
mov(Operand::StaticVariable(context_address), esi);
@@ -518,14 +518,14 @@
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
- ExternalReference context_address(Isolate::k_context_address, isolate());
+ ExternalReference context_address(Isolate::kContextAddress, isolate());
mov(esi, Operand::StaticVariable(context_address));
#ifdef DEBUG
mov(Operand::StaticVariable(context_address), Immediate(0));
#endif
// Clear the top frame.
- ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
isolate());
mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
}
@@ -567,10 +567,10 @@
push(Immediate(Smi::FromInt(0))); // No context.
}
// Save the current handler as the next handler.
- push(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ push(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
isolate())));
// Link this handler as the new current one.
- mov(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ mov(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
isolate())),
esp);
}
@@ -578,7 +578,7 @@
void MacroAssembler::PopTryHandler() {
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
- pop(Operand::StaticVariable(ExternalReference(Isolate::k_handler_address,
+ pop(Operand::StaticVariable(ExternalReference(Isolate::kHandlerAddress,
isolate())));
add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize));
}
@@ -598,7 +598,7 @@
}
// Drop the sp to the top of the handler.
- ExternalReference handler_address(Isolate::k_handler_address,
+ ExternalReference handler_address(Isolate::kHandlerAddress,
isolate());
mov(esp, Operand::StaticVariable(handler_address));
@@ -637,7 +637,7 @@
}
// Drop sp to the top stack handler.
- ExternalReference handler_address(Isolate::k_handler_address,
+ ExternalReference handler_address(Isolate::kHandlerAddress,
isolate());
mov(esp, Operand::StaticVariable(handler_address));
@@ -660,13 +660,13 @@
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address,
+ Isolate::kExternalCaughtExceptionAddress,
isolate());
mov(eax, false);
mov(Operand::StaticVariable(external_caught), eax);
// Set pending exception and eax to out of memory exception.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate());
mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
mov(Operand::StaticVariable(pending_exception), eax);
@@ -840,7 +840,7 @@
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0);
test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
- Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
j(not_zero, miss);
// Get the value at the masked, scaled index.
@@ -1172,7 +1172,7 @@
}
-void MacroAssembler::AllocateConsString(Register result,
+void MacroAssembler::AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
@@ -1208,7 +1208,7 @@
}
-void MacroAssembler::AllocateSlicedString(Register result,
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
index de9361d..1906644 100644
--- a/src/ia32/macro-assembler-ia32.h
+++ b/src/ia32/macro-assembler-ia32.h
@@ -437,7 +437,7 @@
// Allocate a raw cons string object. Only the map field of the result is
// initialized.
- void AllocateConsString(Register result,
+ void AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
@@ -448,7 +448,7 @@
// Allocate a raw sliced string object. Only the map field of the result is
// initialized.
- void AllocateSlicedString(Register result,
+ void AllocateTwoByteSlicedString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 621a9bb..ab62764 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -2679,7 +2679,7 @@
// -- esp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_jsarray, elements_kind).TryGetCode();
@@ -3140,7 +3140,7 @@
// -- esp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(edx,
@@ -3385,7 +3385,7 @@
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3407,29 +3407,29 @@
__ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
// ebx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ SmiUntag(eax); // Untag the index.
__ movsx_b(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ SmiUntag(eax); // Untag the index.
__ movzx_b(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsx_w(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzx_w(eax, Operand(ebx, eax, times_1, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ mov(ecx, Operand(ebx, eax, times_2, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
__ fld_s(Operand(ebx, eax, times_2, 0));
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ fld_d(Operand(ebx, eax, times_4, 0));
break;
default:
@@ -3442,17 +3442,17 @@
// For floating-point array type:
// FP(0): value
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS ||
+ elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// For the Int and UnsignedInt array types, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
Label box_int;
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
__ cmp(ecx, 0xC0000000);
__ j(sign, &box_int);
} else {
- ASSERT_EQ(JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
+ ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
@@ -3468,12 +3468,12 @@
// Allocate a HeapNumber for the int and perform int-to-double
// conversion.
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
__ push(ecx);
__ fild_s(Operand(esp, 0));
__ pop(ecx);
} else {
- ASSERT_EQ(JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
+ ASSERT_EQ(EXTERNAL_UNSIGNED_INT_ELEMENTS, elements_kind);
// Need to zero-extend the value.
// There's no fild variant for unsigned values, so zero-extend
// to a 64-bit int manually.
@@ -3489,8 +3489,8 @@
__ mov(eax, ecx);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
__ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
@@ -3540,7 +3540,7 @@
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
@@ -3566,7 +3566,7 @@
// edx: receiver
// ecx: key
// edi: elements array
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
__ JumpIfNotSmi(eax, &slow);
} else {
__ JumpIfNotSmi(eax, &check_heap_number);
@@ -3578,33 +3578,33 @@
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// edi: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ ClampUint8(ebx);
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ mov(Operand(edi, ecx, times_2, 0), ebx);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion.
__ push(ebx);
__ fild_s(Operand(esp, 0));
__ pop(ebx);
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ fstp_s(Operand(edi, ecx, times_2, 0));
- } else { // elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS.
+ } else { // elements_kind == EXTERNAL_DOUBLE_ELEMENTS.
__ fstp_d(Operand(edi, ecx, times_4, 0));
}
break;
@@ -3615,7 +3615,7 @@
__ ret(0); // Return the original value.
// TODO(danno): handle heap number -> pixel array conversion
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
__ bind(&check_heap_number);
// eax: value
// edx: receiver
@@ -3630,11 +3630,11 @@
// reproducible behavior, convert these to zero.
__ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
// edi: base pointer of external storage
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_s(Operand(edi, ecx, times_2, 0));
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ fstp_d(Operand(edi, ecx, times_4, 0));
__ ret(0);
@@ -3647,23 +3647,23 @@
// (code-stubs-ia32.cc) is roughly what is needed here though the
// conversion failure case does not need to be handled.
if (CpuFeatures::IsSupported(SSE2)) {
- if (elements_kind != JSObject::EXTERNAL_INT_ELEMENTS &&
- elements_kind != JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ if (elements_kind != EXTERNAL_INT_ELEMENTS &&
+ elements_kind != EXTERNAL_UNSIGNED_INT_ELEMENTS) {
ASSERT(CpuFeatures::IsSupported(SSE2));
CpuFeatures::Scope scope(SSE2);
__ cvttsd2si(ebx, FieldOperand(eax, HeapNumber::kValueOffset));
// ecx: untagged integer value
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ ClampUint8(ebx);
// Fall through.
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ SmiUntag(ecx);
__ mov_b(Operand(edi, ecx, times_1, 0), ebx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ mov_w(Operand(edi, ecx, times_1, 0), ebx);
break;
default:
diff --git a/src/ic.cc b/src/ic.cc
index 0d0b935..0f76a9a 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -61,8 +61,7 @@
void IC::TraceIC(const char* type,
Handle<Object> name,
State old_state,
- Code* new_target,
- const char* extra_info) {
+ Code* new_target) {
if (FLAG_trace_ic) {
State new_state = StateFrom(new_target,
HEAP->undefined_value(),
@@ -94,10 +93,9 @@
} else {
PrintF("<unknown>");
}
- PrintF(" (%c->%c)%s",
+ PrintF(" (%c->%c)",
TransitionMarkFromState(old_state),
- TransitionMarkFromState(new_state),
- extra_info);
+ TransitionMarkFromState(new_state));
name->Print();
PrintF("]\n");
}
@@ -326,7 +324,6 @@
Code* code =
Isolate::Current()->stub_cache()->FindCallInitialize(
target->arguments_count(),
- target->ic_in_loop(),
contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
target->kind());
SetTargetAtAddress(address, code);
@@ -604,13 +601,11 @@
Handle<Object> object,
Handle<String> name) {
int argc = target()->arguments_count();
- InLoopFlag in_loop = target()->ic_in_loop();
MaybeObject* maybe_code = NULL;
switch (lookup->type()) {
case FIELD: {
int index = lookup->GetFieldIndex();
maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -626,7 +621,6 @@
JSFunction* function = lookup->GetConstantFunction();
maybe_code =
isolate()->stub_cache()->ComputeCallConstant(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -646,7 +640,6 @@
if (!cell->value()->IsJSFunction()) return NULL;
JSFunction* function = JSFunction::cast(cell->value());
maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -661,7 +654,6 @@
// applicable.
if (lookup->holder() != *receiver) return NULL;
maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
- in_loop,
kind_,
extra_ic_state,
*name,
@@ -706,7 +698,6 @@
// Compute the number of arguments.
int argc = target()->arguments_count();
- InLoopFlag in_loop = target()->ic_in_loop();
MaybeObject* maybe_code = NULL;
bool had_proto_failure = false;
if (state == UNINITIALIZED) {
@@ -715,7 +706,6 @@
// setting the monomorphic state.
maybe_code =
isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
- in_loop,
kind_,
extra_ic_state);
} else if (state == MONOMORPHIC) {
@@ -739,7 +729,6 @@
} else {
maybe_code =
isolate()->stub_cache()->ComputeCallMegamorphic(argc,
- in_loop,
kind_,
extra_ic_state);
}
@@ -776,7 +765,7 @@
#ifdef DEBUG
if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
- name, state, target(), in_loop ? " (in-loop)" : "");
+ name, state, target());
#endif
}
@@ -797,31 +786,28 @@
if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) {
int argc = target()->arguments_count();
- InLoopFlag in_loop = target()->ic_in_loop();
Heap* heap = Handle<HeapObject>::cast(object)->GetHeap();
Map* map = heap->non_strict_arguments_elements_map();
if (object->IsJSObject() &&
Handle<JSObject>::cast(object)->elements()->map() == map) {
MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments(
- argc, in_loop, Code::KEYED_CALL_IC);
+ argc, Code::KEYED_CALL_IC);
Object* code;
if (maybe_code->ToObject(&code)) {
set_target(Code::cast(code));
#ifdef DEBUG
- TraceIC(
- "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
+ TraceIC("KeyedCallIC", key, state, target());
#endif
}
} else if (FLAG_use_ic && state != MEGAMORPHIC &&
!object->IsAccessCheckNeeded()) {
MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
- argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState);
+ argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
Object* code;
if (maybe_code->ToObject(&code)) {
set_target(Code::cast(code));
#ifdef DEBUG
- TraceIC(
- "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
+ TraceIC("KeyedCallIC", key, state, target());
#endif
}
}
@@ -1093,7 +1079,7 @@
MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
return KeyedLoadElementStub(elements_kind).TryGetCode();
}
@@ -1650,7 +1636,6 @@
PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache();
Code::Flags flags = Code::ComputeFlags(this->kind(),
- NOT_IN_LOOP,
MEGAMORPHIC,
strict_mode);
Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags);
@@ -1721,7 +1706,7 @@
MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
}
@@ -1905,16 +1890,11 @@
//
static JSFunction* CompileFunction(Isolate* isolate,
- JSFunction* function,
- InLoopFlag in_loop) {
+ JSFunction* function) {
// Compile now with optimization.
HandleScope scope(isolate);
Handle<JSFunction> function_handle(function, isolate);
- if (in_loop == IN_LOOP) {
- CompileLazyInLoop(function_handle, CLEAR_EXCEPTION);
- } else {
- CompileLazy(function_handle, CLEAR_EXCEPTION);
- }
+ CompileLazy(function_handle, CLEAR_EXCEPTION);
return *function_handle;
}
@@ -1943,9 +1923,7 @@
if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
return result;
}
- return CompileFunction(isolate,
- JSFunction::cast(result),
- ic.target()->ic_in_loop());
+ return CompileFunction(isolate, JSFunction::cast(result));
}
@@ -1964,9 +1942,7 @@
if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
return result;
}
- return CompileFunction(isolate,
- JSFunction::cast(result),
- ic.target()->ic_in_loop());
+ return CompileFunction(isolate, JSFunction::cast(result));
}
diff --git a/src/ic.h b/src/ic.h
index 2236ba3..ece5be9 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -149,8 +149,7 @@
void TraceIC(const char* type,
Handle<Object> name,
State old_state,
- Code* new_target,
- const char* extra_info = "");
+ Code* new_target);
#endif
Failure* TypeError(const char* type,
@@ -348,7 +347,7 @@
virtual MaybeObject* GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind) = 0;
+ ElementsKind elements_kind) = 0;
protected:
virtual Code* string_stub() {
@@ -415,7 +414,7 @@
virtual MaybeObject* GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
@@ -566,7 +565,7 @@
virtual MaybeObject* GetElementStubWithoutMapCheck(
bool is_js_array,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
diff --git a/src/inspector.h b/src/inspector.h
index f8b3042..e328bcd 100644
--- a/src/inspector.h
+++ b/src/inspector.h
@@ -41,7 +41,6 @@
class Inspector {
public:
-
static void DumpObjectType(FILE* out, Object *obj, bool print_more);
static void DumpObjectType(FILE* out, Object *obj) {
DumpObjectType(out, obj, false);
@@ -59,4 +58,3 @@
#endif // INSPECTOR
#endif // V8_INSPECTOR_H_
-
diff --git a/src/isolate.cc b/src/isolate.cc
index 09cbc8a..fd0f673 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -43,7 +43,6 @@
#include "messages.h"
#include "regexp-stack.h"
#include "runtime-profiler.h"
-#include "scanner.h"
#include "scopeinfo.h"
#include "serialize.h"
#include "simulator.h"
@@ -1409,14 +1408,13 @@
global_handles_(NULL),
context_switcher_(NULL),
thread_manager_(NULL),
- ast_sentinels_(NULL),
string_tracker_(NULL),
regexp_stack_(NULL),
embedder_data_(NULL) {
TRACE_ISOLATE(constructor);
memset(isolate_addresses_, 0,
- sizeof(isolate_addresses_[0]) * (k_isolate_address_count + 1));
+ sizeof(isolate_addresses_[0]) * (kIsolateAddressCount + 1));
heap_.isolate_ = this;
zone_.isolate_ = this;
@@ -1546,9 +1544,6 @@
delete regexp_stack_;
regexp_stack_ = NULL;
- delete ast_sentinels_;
- ast_sentinels_ = NULL;
-
delete descriptor_lookup_cache_;
descriptor_lookup_cache_ = NULL;
delete context_slot_cache_;
@@ -1691,9 +1686,10 @@
// ensuring that Isolate::Current() == this.
heap_.SetStackLimits();
-#define C(name) isolate_addresses_[Isolate::k_##name] = \
- reinterpret_cast<Address>(name());
- ISOLATE_ADDRESS_LIST(C)
+#define ASSIGN_ELEMENT(CamelName, hacker_name) \
+ isolate_addresses_[Isolate::k##CamelName##Address] = \
+ reinterpret_cast<Address>(hacker_name##_address());
+ FOR_EACH_ISOLATE_ADDRESS_NAME(ASSIGN_ELEMENT)
#undef C
string_tracker_ = new StringTracker();
@@ -1710,7 +1706,6 @@
bootstrapper_ = new Bootstrapper();
handle_scope_implementer_ = new HandleScopeImplementer(this);
stub_cache_ = new StubCache(this);
- ast_sentinels_ = new AstSentinels();
regexp_stack_ = new RegExpStack();
regexp_stack_->isolate_ = this;
diff --git a/src/isolate.h b/src/isolate.h
index 5bb504d..2582da6 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -47,7 +47,6 @@
namespace v8 {
namespace internal {
-class AstSentinels;
class Bootstrapper;
class CodeGenerator;
class CodeRange;
@@ -120,13 +119,13 @@
#define RETURN_IF_EMPTY_HANDLE(isolate, call) \
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, Failure::Exception())
-#define ISOLATE_ADDRESS_LIST(C) \
- C(handler_address) \
- C(c_entry_fp_address) \
- C(context_address) \
- C(pending_exception_address) \
- C(external_caught_exception_address) \
- C(js_entry_sp_address)
+#define FOR_EACH_ISOLATE_ADDRESS_NAME(C) \
+ C(Handler, handler) \
+ C(CEntryFP, c_entry_fp) \
+ C(Context, context) \
+ C(PendingException, pending_exception) \
+ C(ExternalCaughtException, external_caught_exception) \
+ C(JSEntrySP, js_entry_sp)
// Platform-independent, reliable thread identifier.
@@ -424,10 +423,10 @@
enum AddressId {
-#define C(name) k_##name,
- ISOLATE_ADDRESS_LIST(C)
+#define DECLARE_ENUM(CamelName, hacker_name) k##CamelName##Address,
+ FOR_EACH_ISOLATE_ADDRESS_NAME(DECLARE_ENUM)
#undef C
- k_isolate_address_count
+ kIsolateAddressCount
};
// Returns the PerIsolateThreadData for the current thread (or NULL if one is
@@ -878,8 +877,6 @@
return &objects_string_input_buffer_;
}
- AstSentinels* ast_sentinels() { return ast_sentinels_; }
-
RuntimeState* runtime_state() { return &runtime_state_; }
StaticResource<SafeStringInputBuffer>* compiler_safe_string_input_buffer() {
@@ -1100,7 +1097,7 @@
StringStream* incomplete_message_;
// The preallocated memory thread singleton.
PreallocatedMemoryThread* preallocated_memory_thread_;
- Address isolate_addresses_[k_isolate_address_count + 1]; // NOLINT
+ Address isolate_addresses_[kIsolateAddressCount + 1]; // NOLINT
NoAllocationStringAllocator* preallocated_message_space_;
Bootstrapper* bootstrapper_;
@@ -1138,7 +1135,6 @@
GlobalHandles* global_handles_;
ContextSwitcher* context_switcher_;
ThreadManager* thread_manager_;
- AstSentinels* ast_sentinels_;
RuntimeState runtime_state_;
StaticResource<SafeStringInputBuffer> compiler_safe_string_input_buffer_;
Builtins builtins_;
diff --git a/src/json.js b/src/json.js
index 8fd410f..deba126 100644
--- a/src/json.js
+++ b/src/json.js
@@ -54,7 +54,7 @@
function JSONParse(text, reviver) {
var unfiltered = %ParseJson(TO_STRING_INLINE(text));
- if (IS_FUNCTION(reviver)) {
+ if (IS_SPEC_FUNCTION(reviver)) {
return Revive({'': unfiltered}, '', reviver);
} else {
return unfiltered;
@@ -143,11 +143,11 @@
var value = holder[key];
if (IS_SPEC_OBJECT(value)) {
var toJSON = value.toJSON;
- if (IS_FUNCTION(toJSON)) {
+ if (IS_SPEC_FUNCTION(toJSON)) {
value = %_CallFunction(value, key, toJSON);
}
}
- if (IS_FUNCTION(replacer)) {
+ if (IS_SPEC_FUNCTION(replacer)) {
value = %_CallFunction(holder, key, value, replacer);
}
if (IS_STRING(value)) {
@@ -273,7 +273,7 @@
function BasicJSONSerialize(key, value, stack, builder) {
if (IS_SPEC_OBJECT(value)) {
var toJSON = value.toJSON;
- if (IS_FUNCTION(toJSON)) {
+ if (IS_SPEC_FUNCTION(toJSON)) {
value = %_CallFunction(value, ToString(key), toJSON);
}
}
@@ -337,11 +337,12 @@
return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
}
-function SetupJSON() {
+function SetUpJSON() {
+ %CheckIsBootstrapping();
InstallFunctions($JSON, DONT_ENUM, $Array(
"parse", JSONParse,
"stringify", JSONStringify
));
}
-SetupJSON();
+SetUpJSON()
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 4ca83a4..3ebfbdf 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -2661,7 +2661,8 @@
// this alternative and back to this choice node. If there are variable
// length nodes or other complications in the way then return a sentinel
// value indicating that a greedy loop cannot be constructed.
-int ChoiceNode::GreedyLoopTextLength(GuardedAlternative* alternative) {
+int ChoiceNode::GreedyLoopTextLengthForAlternative(
+ GuardedAlternative* alternative) {
int length = 0;
RegExpNode* node = alternative->node();
// Later we will generate code for all these text nodes using recursion
@@ -2700,7 +2701,8 @@
void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
if (trace->stop_node() == this) {
- int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
+ int text_length =
+ GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
ASSERT(text_length != kNodeIsTooComplexForGreedyLoops);
// Update the counter-based backtracking info on the stack. This is an
// optimization for greedy loops (see below).
@@ -2893,7 +2895,7 @@
Trace* current_trace = trace;
- int text_length = GreedyLoopTextLength(&(alternatives_->at(0)));
+ int text_length = GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
bool greedy_loop = false;
Label greedy_loop_label;
Trace counter_backtrack_trace;
diff --git a/src/jsregexp.h b/src/jsregexp.h
index 13f9e2e..54297a4 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -255,6 +255,7 @@
return (bits_ == (kInFirst | kInSecond | kInBoth));
}
int value() { return bits_; }
+
private:
int bits_;
};
@@ -404,6 +405,7 @@
template <typename Callback>
void ForEach(Callback* callback) { return tree()->ForEach(callback); }
+
private:
// There can't be a static empty set since it allocates its
// successors in a zone and caches them.
@@ -793,6 +795,7 @@
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
virtual ActionNode* Clone() { return new ActionNode(*this); }
virtual int ComputeFirstCharacterSet(int budget);
+
private:
union {
struct {
@@ -861,6 +864,7 @@
}
void CalculateOffsets();
virtual int ComputeFirstCharacterSet(int budget);
+
private:
enum TextEmitPassType {
NON_ASCII_MATCH, // Check for characters that can't match.
@@ -925,6 +929,7 @@
virtual AssertionNode* Clone() { return new AssertionNode(*this); }
AssertionNodeType type() { return type_; }
void set_type(AssertionNodeType type) { type_ = type; }
+
private:
AssertionNode(AssertionNodeType t, RegExpNode* on_success)
: SeqRegExpNode(on_success), type_(t) { }
@@ -955,6 +960,7 @@
}
virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); }
virtual int ComputeFirstCharacterSet(int budget);
+
private:
int start_reg_;
int end_reg_;
@@ -1071,7 +1077,7 @@
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
protected:
- int GreedyLoopTextLength(GuardedAlternative* alternative);
+ int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
ZoneList<GuardedAlternative>* alternatives_;
private:
@@ -1301,6 +1307,7 @@
}
void InvalidateCurrentCharacter();
void AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler);
+
private:
int FindAffectedRegisters(OutSet* affected_registers);
void PerformDeferredActions(RegExpMacroAssembler* macro,
@@ -1402,6 +1409,7 @@
void fail(const char* error_message) {
error_message_ = error_message;
}
+
private:
bool ignore_case_;
bool is_ascii_;
diff --git a/src/list-inl.h b/src/list-inl.h
index 8ef7514..80bccc9 100644
--- a/src/list-inl.h
+++ b/src/list-inl.h
@@ -207,6 +207,35 @@
}
+template <typename T>
+int SortedListBSearch(
+ const List<T>& list, T elem, int (*cmp)(const T* x, const T* y)) {
+ int low = 0;
+ int high = list.length() - 1;
+ while (low <= high) {
+ int mid = (low + high) / 2;
+ T mid_elem = list[mid];
+
+ if (mid_elem > elem) {
+ high = mid - 1;
+ continue;
+ }
+ if (mid_elem < elem) {
+ low = mid + 1;
+ continue;
+ }
+ // Found the elememt.
+ return mid;
+ }
+ return -1;
+}
+
+
+template <typename T>
+int SortedListBSearch(const List<T>& list, T elem) {
+ return SortedListBSearch<T>(list, elem, PointerValueCompare<T>);
+}
+
} } // namespace v8::internal
#endif // V8_LIST_INL_H_
diff --git a/src/list.h b/src/list.h
index ca2b7bc..0558709 100644
--- a/src/list.h
+++ b/src/list.h
@@ -49,7 +49,6 @@
template <typename T, class P>
class List {
public:
-
List() { Initialize(0); }
INLINE(explicit List(int capacity)) { Initialize(capacity); }
INLINE(~List()) { DeleteData(data_); }
@@ -169,6 +168,15 @@
typedef List<Map*> MapList;
typedef List<Code*> CodeList;
+// Perform binary search for an element in an already sorted
+// list. Returns the index of the element of -1 if it was not found.
+template <typename T>
+int SortedListBSearch(
+ const List<T>& list, T elem, int (*cmp)(const T* x, const T* y));
+template <typename T>
+int SortedListBSearch(const List<T>& list, T elem);
+
} } // namespace v8::internal
+
#endif // V8_LIST_H_
diff --git a/src/lithium.cc b/src/lithium.cc
index 64ef469..5410f6f 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -166,25 +166,25 @@
}
-int ElementsKindToShiftSize(JSObject::ElementsKind elements_kind) {
+int ElementsKindToShiftSize(ElementsKind elements_kind) {
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
return 0;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
return 1;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
return 2;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
return 3;
- case JSObject::FAST_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
return kPointerSizeLog2;
}
UNREACHABLE();
diff --git a/src/lithium.h b/src/lithium.h
index 6010b77..20da21a 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -165,8 +165,7 @@
}
Policy policy() const { return PolicyField::decode(value_); }
void set_policy(Policy policy) {
- value_ &= ~PolicyField::mask();
- value_ |= PolicyField::encode(policy);
+ value_ = PolicyField::update(value_, policy);
}
int fixed_index() const {
return static_cast<int>(value_) >> kFixedIndexShift;
@@ -177,8 +176,7 @@
}
void set_virtual_register(unsigned id) {
- value_ &= ~VirtualRegisterField::mask();
- value_ |= VirtualRegisterField::encode(id);
+ value_ = VirtualRegisterField::update(value_, id);
}
LUnallocated* CopyUnconstrained() {
@@ -586,7 +584,7 @@
};
-int ElementsKindToShiftSize(JSObject::ElementsKind elements_kind);
+int ElementsKindToShiftSize(ElementsKind elements_kind);
} } // namespace v8::internal
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 0b01e8a..d44c2fc 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -860,8 +860,7 @@
int j = 0;
for (int i = 0; i < list.length(); i++) {
Variable* var1 = list[i];
- Slot* slot = var1->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ if (var1->IsContextSlot()) {
if (j != i) {
list[j] = var1;
}
@@ -873,7 +872,7 @@
for (int k = 1; k < j; k++) {
int l = k;
for (int m = k + 1; m < j; m++) {
- if (list[l]->AsSlot()->index() > list[m]->AsSlot()->index()) {
+ if (list[l]->index() > list[m]->index()) {
l = m;
}
}
@@ -887,7 +886,7 @@
SetElementNonStrict(
scope_info_list,
scope_info_length,
- Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index())));
+ Handle<Smi>(Smi::FromInt(list[i]->index())));
scope_info_length++;
}
SetElementNonStrict(scope_info_list,
@@ -1451,7 +1450,7 @@
StackFrame* bottom_frame) {
Address* pointer_address =
&Memory::Address_at(Isolate::Current()->get_address_from_id(
- Isolate::k_handler_address));
+ Isolate::kHandlerAddress));
while (*pointer_address < top_frame->sp()) {
pointer_address = &Memory::Address_at(*pointer_address);
diff --git a/src/liveobjectlist.cc b/src/liveobjectlist.cc
index 451a28a..957c051 100644
--- a/src/liveobjectlist.cc
+++ b/src/liveobjectlist.cc
@@ -184,7 +184,7 @@
const AllocationSpace kInvalidSpace = static_cast<AllocationSpace>(-1);
static AllocationSpace FindSpaceFor(String* space_str) {
- SmartPointer<char> s =
+ SmartArrayPointer<char> s =
space_str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
const char* key_str = *s;
@@ -236,7 +236,7 @@
static LiveObjectType FindTypeFor(String* type_str) {
- SmartPointer<char> s =
+ SmartArrayPointer<char> s =
type_str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
#define CHECK_OBJECT_TYPE(type_, name) { \
@@ -503,10 +503,10 @@
// We'll only dump 80 of them after we compact them.
const int kMaxCharToDump = 80;
const int kMaxBufferSize = kMaxCharToDump * 2;
- SmartPointer<char> str_sp = str->ToCString(DISALLOW_NULLS,
- ROBUST_STRING_TRAVERSAL,
- 0,
- kMaxBufferSize);
+ SmartArrayPointer<char> str_sp = str->ToCString(DISALLOW_NULLS,
+ ROBUST_STRING_TRAVERSAL,
+ 0,
+ kMaxBufferSize);
char* str_cstr = *str_sp;
int length = CompactString(str_cstr);
OS::SNPrintF(buffer_v,
@@ -526,14 +526,14 @@
}
String* name = sinfo->DebugName();
- SmartPointer<char> name_sp =
+ SmartArrayPointer<char> name_sp =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
char* name_cstr = *name_sp;
HeapStringAllocator string_allocator;
StringStream stream(&string_allocator);
sinfo->SourceCodePrint(&stream, 50);
- SmartPointer<const char> source_sp = stream.ToCString();
+ SmartArrayPointer<const char> source_sp = stream.ToCString();
const char* source_cstr = *source_sp;
OS::SNPrintF(buffer_v,
@@ -1656,7 +1656,7 @@
// Gets the obj id for the specified address if valid.
Object* LiveObjectList::GetObjId(Handle<String> address) {
- SmartPointer<char> addr_str =
+ SmartArrayPointer<char> addr_str =
address->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
Isolate* isolate = Isolate::Current();
diff --git a/src/liveobjectlist.h b/src/liveobjectlist.h
index 542482d..65470d7 100644
--- a/src/liveobjectlist.h
+++ b/src/liveobjectlist.h
@@ -114,7 +114,6 @@
static Object* PrintObj(int obj_id);
private:
-
struct Element {
int id_;
HeapObject* obj_;
@@ -224,7 +223,6 @@
// Helper class for updating the LiveObjectList HeapObject pointers.
class UpdateLiveObjectListVisitor: public ObjectVisitor {
public:
-
void VisitPointer(Object** p) { UpdatePointer(p); }
void VisitPointers(Object** start, Object** end) {
@@ -319,4 +317,3 @@
} } // namespace v8::internal
#endif // V8_LIVEOBJECTLIST_H_
-
diff --git a/src/log-utils.cc b/src/log-utils.cc
index 27e654d..7bd7baa 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -125,7 +125,7 @@
stream.Put(*p);
}
}
- SmartPointer<const char> expanded = stream.ToCString();
+ SmartArrayPointer<const char> expanded = stream.ToCString();
OpenFile(*expanded);
} else {
OpenFile(FLAG_logfile);
diff --git a/src/log-utils.h b/src/log-utils.h
index 2b20a01..d0cb828 100644
--- a/src/log-utils.h
+++ b/src/log-utils.h
@@ -141,7 +141,6 @@
void WriteToLogFile();
private:
-
Log* log_;
ScopedLock sl;
int pos_;
diff --git a/src/log.cc b/src/log.cc
index dedf7e9..3d66b5f 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -617,7 +617,7 @@
void Logger::ApiNamedSecurityCheck(Object* key) {
if (!log_->IsEnabled() || !FLAG_log_api) return;
if (key->IsString()) {
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,check-security,\"%s\"\n", *str);
} else if (key->IsUndefined()) {
@@ -762,9 +762,9 @@
ASSERT(name->IsString());
if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
- SmartPointer<char> class_name =
+ SmartArrayPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- SmartPointer<char> property_name =
+ SmartArrayPointer<char> property_name =
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
}
@@ -774,7 +774,7 @@
uint32_t index) {
if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = holder->class_name();
- SmartPointer<char> class_name =
+ SmartArrayPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
}
@@ -782,7 +782,7 @@
void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = object->class_name();
- SmartPointer<char> class_name =
+ SmartArrayPointer<char> class_name =
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
ApiEvent("api,%s,\"%s\"\n", tag, *class_name);
}
@@ -836,7 +836,7 @@
void Logger::CallbackEvent(String* name, Address entry_point) {
if (!log_->IsEnabled() || !FLAG_log_code) return;
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("", *str, entry_point);
}
@@ -844,7 +844,7 @@
void Logger::GetterCallbackEvent(String* name, Address entry_point) {
if (!log_->IsEnabled() || !FLAG_log_code) return;
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("get ", *str, entry_point);
}
@@ -852,7 +852,7 @@
void Logger::SetterCallbackEvent(String* name, Address entry_point) {
if (!log_->IsEnabled() || !FLAG_log_code) return;
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("set ", *str, entry_point);
}
@@ -957,7 +957,7 @@
return;
LogMessageBuilder msg(this);
- SmartPointer<char> str =
+ SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
@@ -998,9 +998,9 @@
}
if (!FLAG_log_code) return;
LogMessageBuilder msg(this);
- SmartPointer<char> name =
+ SmartArrayPointer<char> name =
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- SmartPointer<char> sourcestr =
+ SmartArrayPointer<char> sourcestr =
source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
@@ -1527,6 +1527,51 @@
}
+void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
+ Handle<Code> code) {
+ Handle<String> func_name(shared->DebugName());
+ if (shared->script()->IsScript()) {
+ Handle<Script> script(Script::cast(shared->script()));
+ if (script->name()->IsString()) {
+ Handle<String> script_name(String::cast(script->name()));
+ int line_num = GetScriptLineNumber(script, shared->start_position());
+ if (line_num > 0) {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code, *shared,
+ *script_name, line_num + 1));
+ } else {
+ // Can't distinguish eval and script here, so always use Script.
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+ *code, *shared, *script_name));
+ }
+ } else {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code, *shared, *func_name));
+ }
+ } else if (shared->IsApiFunction()) {
+ // API function.
+ FunctionTemplateInfo* fun_data = shared->get_api_func_data();
+ Object* raw_call_data = fun_data->call_code();
+ if (!raw_call_data->IsUndefined()) {
+ CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
+ Object* callback_obj = call_data->callback();
+ Address entry_point = v8::ToCData<Address>(callback_obj);
+ PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
+ }
+ } else {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::LAZY_COMPILE_TAG, *code, *shared, *func_name));
+ }
+}
+
+
void Logger::LogCompiledFunctions() {
HandleScope scope;
const int compiled_funcs_count = EnumerateCompiledFunctions(NULL, NULL);
@@ -1540,48 +1585,7 @@
if (*code_objects[i] == Isolate::Current()->builtins()->builtin(
Builtins::kLazyCompile))
continue;
- Handle<SharedFunctionInfo> shared = sfis[i];
- Handle<String> func_name(shared->DebugName());
- if (shared->script()->IsScript()) {
- Handle<Script> script(Script::cast(shared->script()));
- if (script->name()->IsString()) {
- Handle<String> script_name(String::cast(script->name()));
- int line_num = GetScriptLineNumber(script, shared->start_position());
- if (line_num > 0) {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared,
- *script_name, line_num + 1));
- } else {
- // Can't distinguish eval and script here, so always use Script.
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
- *code_objects[i], *shared, *script_name));
- }
- } else {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared, *func_name));
- }
- } else if (shared->IsApiFunction()) {
- // API function.
- FunctionTemplateInfo* fun_data = shared->get_api_func_data();
- Object* raw_call_data = fun_data->call_code();
- if (!raw_call_data->IsUndefined()) {
- CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
- Object* callback_obj = call_data->callback();
- Address entry_point = v8::ToCData<Address>(callback_obj);
- PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
- }
- } else {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::LAZY_COMPILE_TAG, *code_objects[i],
- *shared, *func_name));
- }
+ LogExistingFunction(sfis[i], code_objects[i]);
}
}
diff --git a/src/log.h b/src/log.h
index 31d8404..50358ce 100644
--- a/src/log.h
+++ b/src/log.h
@@ -281,6 +281,8 @@
void ResumeProfiler();
bool IsProfilerPaused();
+ void LogExistingFunction(Handle<SharedFunctionInfo> shared,
+ Handle<Code> code);
// Logs all compiled functions found in the heap.
void LogCompiledFunctions();
// Logs all accessor callbacks found in the heap.
diff --git a/src/macros.py b/src/macros.py
index 5ba7ac3..7a493ca 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -116,13 +116,21 @@
# Macro for ECMAScript 5 queries of the type:
# "Type(O) is object."
-# This is the same as being either a function or an object in V8 terminology.
+# This is the same as being either a function or an object in V8 terminology
+# (including proxies).
# In addition, an undetectable object is also included by this.
-macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
+macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
+
+# Macro for ECMAScript 5 queries of the type:
+# "IsCallable(O)"
+# We assume here that this is the same as being either a function or a function
+# proxy. That ignores host objects with [[Call]] methods, but in most situations
+# we cannot handle those anyway.
+macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === 'Function');
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
-macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || arg - arg == 0);
+macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
@@ -170,7 +178,7 @@
const CAPTURE0 = 3;
const CAPTURE1 = 4;
-# PropertyDescriptor return value indices - must match
+# PropertyDescriptor return value indices - must match
# PropertyDescriptorIndices in runtime.cc.
const IS_ACCESSOR_INDEX = 0;
const VALUE_INDEX = 1;
@@ -179,3 +187,17 @@
const WRITABLE_INDEX = 4;
const ENUMERABLE_INDEX = 5;
const CONFIGURABLE_INDEX = 6;
+
+# For messages.js
+# Matches Script::Type from objects.h
+const TYPE_NATIVE = 0;
+const TYPE_EXTENSION = 1;
+const TYPE_NORMAL = 2;
+
+# Matches Script::CompilationType from objects.h
+const COMPILATION_TYPE_HOST = 0;
+const COMPILATION_TYPE_EVAL = 1;
+const COMPILATION_TYPE_JSON = 2;
+
+# Matches Messages::kNoLineNumberInfo from v8.h
+const kNoLineNumberInfo = 0;
diff --git a/src/math.js b/src/math.js
index 70b8c57..b5a6d18 100644
--- a/src/math.js
+++ b/src/math.js
@@ -38,7 +38,7 @@
function MathConstructor() {}
%FunctionSetInstanceClassName(MathConstructor, 'Math');
const $Math = new MathConstructor();
-$Math.__proto__ = global.Object.prototype;
+$Math.__proto__ = $Object.prototype;
%SetProperty(global, "Math", $Math, DONT_ENUM);
// ECMA 262 - 15.8.2.1
@@ -195,8 +195,9 @@
// -------------------------------------------------------------------
-function SetupMath() {
- // Setup math constants.
+function SetUpMath() {
+ %CheckIsBootstrapping();
+ // Set up math constants.
// ECMA-262, section 15.8.1.1.
%OptimizeObjectForAddingMultipleProperties($Math, 8);
%SetProperty($Math,
@@ -236,7 +237,7 @@
DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Math);
- // Setup non-enumerable functions of the Math object and
+ // Set up non-enumerable functions of the Math object and
// set their names.
InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array(
"random", MathRandom,
@@ -258,7 +259,6 @@
"max", MathMax,
"min", MathMin
));
-};
+}
-
-SetupMath();
+SetUpMath();
diff --git a/src/messages.cc b/src/messages.cc
index 4cbf0af..b6ad5ac 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -41,13 +41,13 @@
// by default.
void MessageHandler::DefaultMessageReport(const MessageLocation* loc,
Handle<Object> message_obj) {
- SmartPointer<char> str = GetLocalizedMessage(message_obj);
+ SmartArrayPointer<char> str = GetLocalizedMessage(message_obj);
if (loc == NULL) {
PrintF("%s\n", *str);
} else {
HandleScope scope;
Handle<Object> data(loc->script()->name());
- SmartPointer<char> data_str;
+ SmartArrayPointer<char> data_str;
if (data->IsString())
data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
PrintF("%s:%i: %s\n", *data_str ? *data_str : "<unknown>",
@@ -170,7 +170,8 @@
}
-SmartPointer<char> MessageHandler::GetLocalizedMessage(Handle<Object> data) {
+SmartArrayPointer<char> MessageHandler::GetLocalizedMessage(
+ Handle<Object> data) {
HandleScope scope;
return GetMessage(data)->ToCString(DISALLOW_NULLS);
}
diff --git a/src/messages.h b/src/messages.h
index fc2162d..358509e 100644
--- a/src/messages.h
+++ b/src/messages.h
@@ -105,7 +105,7 @@
static void DefaultMessageReport(const MessageLocation* loc,
Handle<Object> message_obj);
static Handle<String> GetMessage(Handle<Object> data);
- static SmartPointer<char> GetLocalizedMessage(Handle<Object> data);
+ static SmartArrayPointer<char> GetLocalizedMessage(Handle<Object> data);
};
} } // namespace v8::internal
diff --git a/src/messages.js b/src/messages.js
index 845ca07..a9993af 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -28,27 +28,14 @@
// -------------------------------------------------------------------
//
-// Matches Script::Type from objects.h
-var TYPE_NATIVE = 0;
-var TYPE_EXTENSION = 1;
-var TYPE_NORMAL = 2;
-
-// Matches Script::CompilationType from objects.h
-var COMPILATION_TYPE_HOST = 0;
-var COMPILATION_TYPE_EVAL = 1;
-var COMPILATION_TYPE_JSON = 2;
-
-// Matches Messages::kNoLineNumberInfo from v8.h
-var kNoLineNumberInfo = 0;
-
// If this object gets passed to an error constructor the error will
// get an accessor for .message that constructs a descriptive error
// message on access.
-var kAddMessageAccessorsMarker = { };
+const kAddMessageAccessorsMarker = { };
-var kMessages = 0;
-
-var kReplacementMarkers = [ "%0", "%1", "%2", "%3" ];
+// This will be lazily initialized when first needed (and forcibly
+// overwritten even though it's const).
+const kMessages = 0;
function FormatString(format, message) {
var args = %MessageGetArguments(message);
@@ -56,14 +43,16 @@
var arg_num = 0;
for (var i = 0; i < format.length; i++) {
var str = format[i];
- for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) {
- if (str == kReplacementMarkers[arg_num]) {
+ if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
+ // Two-char string starts with "%".
+ var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
+ if (arg_num < 4) {
+ // str is one of %0, %1, %2 or %3.
try {
str = ToDetailString(args[arg_num]);
} catch (e) {
str = "#<error>";
}
- break;
}
}
result += str;
@@ -102,18 +91,16 @@
function ToDetailString(obj) {
- if (obj != null && IS_OBJECT(obj) &&
- obj.toString === $Object.prototype.toString) {
+ if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
var constructor = obj.constructor;
- if (!constructor) return ToStringCheckErrorObject(obj);
- var constructorName = constructor.name;
- if (!constructorName || !IS_STRING(constructorName)) {
- return ToStringCheckErrorObject(obj);
+ if (typeof constructor == "function") {
+ var constructorName = constructor.name;
+ if (IS_STRING(constructorName) && constructorName !== "") {
+ return "#<" + constructorName + ">";
+ }
}
- return "#<" + constructorName + ">";
- } else {
- return ToStringCheckErrorObject(obj);
}
+ return ToStringCheckErrorObject(obj);
}
@@ -129,10 +116,11 @@
/**
- * Setup the Script function and constructor.
+ * Set up the Script function and constructor.
*/
%FunctionSetInstanceClassName(Script, 'Script');
-%SetProperty(Script.prototype, 'constructor', Script, DONT_ENUM);
+%SetProperty(Script.prototype, 'constructor', Script,
+ DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetCode(Script, function(x) {
// Script objects can only be created by the VM.
throw new $Error("Not supported");
@@ -142,118 +130,135 @@
// Helper functions; called from the runtime system.
function FormatMessage(message) {
if (kMessages === 0) {
- kMessages = {
+ var messagesDictionary = [
// Error
- cyclic_proto: ["Cyclic __proto__ value"],
- code_gen_from_strings: ["Code generation from strings disallowed for this context"],
+ "cyclic_proto", ["Cyclic __proto__ value"],
+ "code_gen_from_strings", ["Code generation from strings disallowed for this context"],
// TypeError
- unexpected_token: ["Unexpected token ", "%0"],
- unexpected_token_number: ["Unexpected number"],
- unexpected_token_string: ["Unexpected string"],
- unexpected_token_identifier: ["Unexpected identifier"],
- unexpected_reserved: ["Unexpected reserved word"],
- unexpected_strict_reserved: ["Unexpected strict mode reserved word"],
- unexpected_eos: ["Unexpected end of input"],
- malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"],
- unterminated_regexp: ["Invalid regular expression: missing /"],
- regexp_flags: ["Cannot supply flags when constructing one RegExp from another"],
- incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"],
- invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
- invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"],
- invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"],
- invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"],
- multiple_defaults_in_switch: ["More than one default clause in switch statement"],
- newline_after_throw: ["Illegal newline after throw"],
- redeclaration: ["%0", " '", "%1", "' has already been declared"],
- no_catch_or_finally: ["Missing catch or finally after try"],
- unknown_label: ["Undefined label '", "%0", "'"],
- uncaught_exception: ["Uncaught ", "%0"],
- stack_trace: ["Stack Trace:\n", "%0"],
- called_non_callable: ["%0", " is not a function"],
- undefined_method: ["Object ", "%1", " has no method '", "%0", "'"],
- property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"],
- cannot_convert_to_primitive: ["Cannot convert object to primitive value"],
- not_constructor: ["%0", " is not a constructor"],
- not_defined: ["%0", " is not defined"],
- non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"],
- non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"],
- non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"],
- with_expression: ["%0", " has no properties"],
- illegal_invocation: ["Illegal invocation"],
- no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
- apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
- apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"],
- invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
- instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"],
- instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"],
- null_to_object: ["Cannot convert null to object"],
- reduce_no_initial: ["Reduce of empty array with no initial value"],
- getter_must_be_callable: ["Getter must be a function: ", "%0"],
- setter_must_be_callable: ["Setter must be a function: ", "%0"],
- value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value: ", "%0"],
- proto_object_or_null: ["Object prototype may only be an Object or null"],
- property_desc_object: ["Property description must be an object: ", "%0"],
- redefine_disallowed: ["Cannot redefine property: ", "%0"],
- define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."],
- non_extensible_proto: ["%0", " is not extensible"],
- handler_non_object: ["Proxy.", "%0", " called with non-object as handler"],
- handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
- handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
- handler_returned_false: ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
- handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
- proxy_prop_not_configurable: ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
- proxy_non_object_prop_names: ["Trap ", "%1", " returned non-object ", "%0"],
- proxy_repeated_prop_name: ["Trap ", "%1", " returned repeated property name ", "%2"],
- invalid_weakmap_key: ["Invalid value used as weak map key"],
+ "unexpected_token", ["Unexpected token ", "%0"],
+ "unexpected_token_number", ["Unexpected number"],
+ "unexpected_token_string", ["Unexpected string"],
+ "unexpected_token_identifier", ["Unexpected identifier"],
+ "unexpected_reserved", ["Unexpected reserved word"],
+ "unexpected_strict_reserved", ["Unexpected strict mode reserved word"],
+ "unexpected_eos", ["Unexpected end of input"],
+ "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"],
+ "unterminated_regexp", ["Invalid regular expression: missing /"],
+ "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"],
+ "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
+ "invalid_lhs_in_assignment", ["Invalid left-hand side in assignment"],
+ "invalid_lhs_in_for_in", ["Invalid left-hand side in for-in"],
+ "invalid_lhs_in_postfix_op", ["Invalid left-hand side expression in postfix operation"],
+ "invalid_lhs_in_prefix_op", ["Invalid left-hand side expression in prefix operation"],
+ "multiple_defaults_in_switch", ["More than one default clause in switch statement"],
+ "newline_after_throw", ["Illegal newline after throw"],
+ "redeclaration", ["%0", " '", "%1", "' has already been declared"],
+ "no_catch_or_finally", ["Missing catch or finally after try"],
+ "unknown_label", ["Undefined label '", "%0", "'"],
+ "uncaught_exception", ["Uncaught ", "%0"],
+ "stack_trace", ["Stack Trace:\n", "%0"],
+ "called_non_callable", ["%0", " is not a function"],
+ "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"],
+ "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"],
+ "cannot_convert_to_primitive", ["Cannot convert object to primitive value"],
+ "not_constructor", ["%0", " is not a constructor"],
+ "not_defined", ["%0", " is not defined"],
+ "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"],
+ "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"],
+ "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"],
+ "with_expression", ["%0", " has no properties"],
+ "illegal_invocation", ["Illegal invocation"],
+ "no_setter_in_callback", ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
+ "apply_non_function", ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
+ "apply_wrong_args", ["Function.prototype.apply: Arguments list has wrong type"],
+ "invalid_in_operator_use", ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
+ "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
+ "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"],
+ "null_to_object", ["Cannot convert null to object"],
+ "reduce_no_initial", ["Reduce of empty array with no initial value"],
+ "getter_must_be_callable", ["Getter must be a function: ", "%0"],
+ "setter_must_be_callable", ["Setter must be a function: ", "%0"],
+ "value_and_accessor", ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"],
+ "proto_object_or_null", ["Object prototype may only be an Object or null"],
+ "property_desc_object", ["Property description must be an object: ", "%0"],
+ "redefine_disallowed", ["Cannot redefine property: ", "%0"],
+ "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."],
+ "non_extensible_proto", ["%0", " is not extensible"],
+ "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"],
+ "trap_function_expected", ["Proxy.", "%0", " called with non-function for ", "%1", " trap"],
+ "handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
+ "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
+ "handler_returned_false", ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
+ "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
+ "proxy_prop_not_configurable", ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
+ "proxy_non_object_prop_names", ["Trap ", "%1", " returned non-object ", "%0"],
+ "proxy_repeated_prop_name", ["Trap ", "%1", " returned repeated property name ", "%2"],
+ "invalid_weakmap_key", ["Invalid value used as weak map key"],
// RangeError
- invalid_array_length: ["Invalid array length"],
- stack_overflow: ["Maximum call stack size exceeded"],
+ "invalid_array_length", ["Invalid array length"],
+ "stack_overflow", ["Maximum call stack size exceeded"],
// SyntaxError
- unable_to_parse: ["Parse error"],
- invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
- invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"],
- illegal_break: ["Illegal break statement"],
- illegal_continue: ["Illegal continue statement"],
- illegal_return: ["Illegal return statement"],
- error_loading_debugger: ["Error loading debugger"],
- no_input_to_regexp: ["No input to ", "%0"],
- invalid_json: ["String '", "%0", "' is not valid JSON"],
- circular_structure: ["Converting circular structure to JSON"],
- obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"],
- called_on_null_or_undefined: ["%0", " called on null or undefined"],
- array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
- object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
- illegal_access: ["Illegal access"],
- invalid_preparser_data: ["Invalid preparser data for function ", "%0"],
- strict_mode_with: ["Strict mode code may not include a with statement"],
- strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"],
- too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"],
- too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"],
- too_many_variables: ["Too many variables declared (only 32767 allowed)"],
- strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"],
- strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
- strict_var_name: ["Variable name may not be eval or arguments in strict mode"],
- strict_function_name: ["Function name may not be eval or arguments in strict mode"],
- strict_octal_literal: ["Octal literals are not allowed in strict mode."],
- strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"],
- accessor_data_property: ["Object literal may not have data and accessor property with the same name"],
- accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"],
- strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"],
- strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
- strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
- strict_reserved_word: ["Use of future reserved word in strict mode"],
- strict_delete: ["Delete of an unqualified identifier in strict mode."],
- strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"],
- strict_const: ["Use of const in strict mode."],
- strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
- strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"],
- strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"],
- strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
- strict_caller: ["Illegal access to a strict mode caller function."],
- unprotected_let: ["Illegal let declaration in unprotected statement context."],
- cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
- redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
- };
+ "unable_to_parse", ["Parse error"],
+ "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
+ "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"],
+ "illegal_break", ["Illegal break statement"],
+ "illegal_continue", ["Illegal continue statement"],
+ "illegal_return", ["Illegal return statement"],
+ "error_loading_debugger", ["Error loading debugger"],
+ "no_input_to_regexp", ["No input to ", "%0"],
+ "invalid_json", ["String '", "%0", "' is not valid JSON"],
+ "circular_structure", ["Converting circular structure to JSON"],
+ "obj_ctor_property_non_object", ["Object.", "%0", " called on non-object"],
+ "called_on_null_or_undefined", ["%0", " called on null or undefined"],
+ "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"],
+ "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"],
+ "illegal_access", ["Illegal access"],
+ "invalid_preparser_data", ["Invalid preparser data for function ", "%0"],
+ "strict_mode_with", ["Strict mode code may not include a with statement"],
+ "strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"],
+ "too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"],
+ "too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"],
+ "too_many_variables", ["Too many variables declared (only 32767 allowed)"],
+ "strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"],
+ "strict_param_dupe", ["Strict mode function may not have duplicate parameter names"],
+ "strict_var_name", ["Variable name may not be eval or arguments in strict mode"],
+ "strict_function_name", ["Function name may not be eval or arguments in strict mode"],
+ "strict_octal_literal", ["Octal literals are not allowed in strict mode."],
+ "strict_duplicate_property", ["Duplicate data property in object literal not allowed in strict mode"],
+ "accessor_data_property", ["Object literal may not have data and accessor property with the same name"],
+ "accessor_get_set", ["Object literal may not have multiple get/set accessors with the same name"],
+ "strict_lhs_assignment", ["Assignment to eval or arguments is not allowed in strict mode"],
+ "strict_lhs_postfix", ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
+ "strict_lhs_prefix", ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
+ "strict_reserved_word", ["Use of future reserved word in strict mode"],
+ "strict_delete", ["Delete of an unqualified identifier in strict mode."],
+ "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"],
+ "strict_const", ["Use of const in strict mode."],
+ "strict_function", ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
+ "strict_read_only_property", ["Cannot assign to read only property '", "%0", "' of ", "%1"],
+ "strict_cannot_assign", ["Cannot assign to read only '", "%0", "' in strict mode"],
+ "strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
+ "strict_caller", ["Illegal access to a strict mode caller function."],
+ "unprotected_let", ["Illegal let declaration in unprotected statement context."],
+ "cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"],
+ "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
+ ];
+ var messages = { __proto__ : null };
+ var desc = new PropertyDescriptor();
+ desc.setConfigurable(false);
+ desc.setEnumerable(false);
+ desc.setWritable(false);
+ for (var i = 0; i < messagesDictionary.length; i += 2) {
+ var key = messagesDictionary[i];
+ var format = messagesDictionary[i + 1];
+ ObjectFreeze(format);
+ desc.setValue(format);
+ DefineOwnProperty(messages, key, desc);
+ }
+ %PreventExtensions(messages);
+ %IgnoreAttributesAndSetProperty(builtins, "kMessages",
+ messages,
+ DONT_DELETE | DONT_ENUM | READ_ONLY);
}
var message_type = %MessageGetType(message);
var format = kMessages[message_type];
@@ -319,7 +324,7 @@
* @return {number} 0 if input too small, -1 if input too large,
else the line number.
*/
-Script.prototype.lineFromPosition = function(position) {
+function ScriptLineFromPosition(position) {
var lower = 0;
var upper = this.lineCount() - 1;
var line_ends = this.line_ends;
@@ -358,8 +363,8 @@
* @return {SourceLocation}
* If line is negative or not in the source null is returned.
*/
-Script.prototype.locationFromPosition = function (position,
- include_resource_offset) {
+function ScriptLocationFromPosition(position,
+ include_resource_offset) {
var line = this.lineFromPosition(position);
if (line == -1) return null;
@@ -367,7 +372,9 @@
var line_ends = this.line_ends;
var start = line == 0 ? 0 : line_ends[line - 1] + 1;
var end = line_ends[line];
- if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') end--;
+ if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
+ end--;
+ }
var column = position - start;
// Adjust according to the offset within the resource.
@@ -392,11 +399,12 @@
* @param {number} opt_line The line within the source. Default value is 0
* @param {number} opt_column The column in within the line. Default value is 0
* @param {number} opt_offset_position The offset from the begining of the
- * source from where the line and column calculation starts. Default value is 0
+ * source from where the line and column calculation starts.
+ * Default value is 0
* @return {SourceLocation}
* If line is negative or not in the source null is returned.
*/
-Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_position) {
+function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
// Default is the first line in the script. Lines in the script is relative
// to the offset within the resource.
var line = 0;
@@ -438,7 +446,7 @@
* @return {SourceSlice} The source slice or null of the parameters where
* invalid
*/
-Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
+function ScriptSourceSlice(opt_from_line, opt_to_line) {
var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset : opt_from_line;
var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line
@@ -465,7 +473,7 @@
}
-Script.prototype.sourceLine = function (opt_line) {
+function ScriptSourceLine(opt_line) {
// Default is the first line in the script. Lines in the script are relative
// to the offset within the resource.
var line = 0;
@@ -491,7 +499,7 @@
* @return {number}
* Number of source lines.
*/
-Script.prototype.lineCount = function() {
+function ScriptLineCount() {
// Return number of source lines.
return this.line_ends.length;
};
@@ -507,9 +515,10 @@
* @return {?string} script name if present, value for //@ sourceURL comment
* otherwise.
*/
-Script.prototype.nameOrSourceURL = function() {
- if (this.name)
+function ScriptNameOrSourceURL() {
+ if (this.name) {
return this.name;
+ }
// TODO(608): the spaces in a regexp below had to be escaped as \040
// because this file is being processed by js2c whose handling of spaces
// in regexps is broken. Also, ['"] are excluded from allowed URLs to
@@ -535,6 +544,20 @@
}
+SetUpLockedPrototype(Script,
+ $Array("source", "name", "line_ends", "line_offset", "column_offset"),
+ $Array(
+ "lineFromPosition", ScriptLineFromPosition,
+ "locationFromPosition", ScriptLocationFromPosition,
+ "locationFromLine", ScriptLocationFromLine,
+ "sourceSlice", ScriptSourceSlice,
+ "sourceLine", ScriptSourceLine,
+ "lineCount", ScriptLineCount,
+ "nameOrSourceURL", ScriptNameOrSourceURL
+ )
+);
+
+
/**
* Class for source location. A source location is a position within some
* source with the following properties:
@@ -565,8 +588,6 @@
this.end = end;
}
-SourceLocation.prototype.__proto__ = null;
-
const kLineLengthLimit = 78;
/**
@@ -577,7 +598,7 @@
* @param {number} opt_before The number of characters to prefer before the
* position with a default value of 10 less that the limit
*/
-SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
+function SourceLocationRestrict(opt_limit, opt_before) {
// Find the actual limit to use.
var limit;
var before;
@@ -624,11 +645,20 @@
* @return {String}
* Source text for this location.
*/
-SourceLocation.prototype.sourceText = function () {
+function SourceLocationSourceText() {
return %_CallFunction(this.script.source, this.start, this.end, StringSubstring);
};
+SetUpLockedPrototype(SourceLocation,
+ $Array("script", "position", "line", "column", "start", "end"),
+ $Array(
+ "restrict", SourceLocationRestrict,
+ "sourceText", SourceLocationSourceText
+ )
+);
+
+
/**
* Class for a source slice. A source slice is a part of a script source with
* the following properties:
@@ -655,20 +685,23 @@
this.to_position = to_position;
}
-SourceSlice.prototype.__proto__ = null;
-
/**
* Get the source text for a SourceSlice
* @return {String} Source text for this slice. The last line will include
* the line terminating characters (if any)
*/
-SourceSlice.prototype.sourceText = function () {
+function SourceSliceSourceText() {
return %_CallFunction(this.script.source,
this.from_position,
this.to_position,
StringSubstring);
};
+SetUpLockedPrototype(SourceSlice,
+ $Array("script", "from_line", "to_line", "from_position", "to_position"),
+ $Array("sourceText", SourceSliceSourceText)
+);
+
// Returns the offset of the given position within the containing
// line.
@@ -723,13 +756,11 @@
this.pos = pos;
}
-CallSite.prototype.__proto__ = null;
-
-CallSite.prototype.getThis = function () {
+function CallSiteGetThis() {
return this.receiver;
};
-CallSite.prototype.getTypeName = function () {
+function CallSiteGetTypeName() {
var constructor = this.receiver.constructor;
if (!constructor) {
return %_CallFunction(this.receiver, ObjectToString);
@@ -741,33 +772,33 @@
return constructorName;
};
-CallSite.prototype.isToplevel = function () {
+function CallSiteIsToplevel() {
if (this.receiver == null) {
return true;
}
return IS_GLOBAL(this.receiver);
};
-CallSite.prototype.isEval = function () {
+function CallSiteIsEval() {
var script = %FunctionGetScript(this.fun);
return script && script.compilation_type == COMPILATION_TYPE_EVAL;
};
-CallSite.prototype.getEvalOrigin = function () {
+function CallSiteGetEvalOrigin() {
var script = %FunctionGetScript(this.fun);
return FormatEvalOrigin(script);
};
-CallSite.prototype.getScriptNameOrSourceURL = function () {
+function CallSiteGetScriptNameOrSourceURL() {
var script = %FunctionGetScript(this.fun);
return script ? script.nameOrSourceURL() : null;
};
-CallSite.prototype.getFunction = function () {
+function CallSiteGetFunction() {
return this.fun;
};
-CallSite.prototype.getFunctionName = function () {
+function CallSiteGetFunctionName() {
// See if the function knows its own name
var name = this.fun.name;
if (name) {
@@ -783,7 +814,7 @@
return null;
};
-CallSite.prototype.getMethodName = function () {
+function CallSiteGetMethodName() {
// See if we can find a unique property on the receiver that holds
// this function.
var ownName = this.fun.name;
@@ -813,12 +844,12 @@
return null;
};
-CallSite.prototype.getFileName = function () {
+function CallSiteGetFileName() {
var script = %FunctionGetScript(this.fun);
return script ? script.name : null;
};
-CallSite.prototype.getLineNumber = function () {
+function CallSiteGetLineNumber() {
if (this.pos == -1) {
return null;
}
@@ -830,7 +861,7 @@
return location ? location.line + 1 : null;
};
-CallSite.prototype.getColumnNumber = function () {
+function CallSiteGetColumnNumber() {
if (this.pos == -1) {
return null;
}
@@ -842,16 +873,16 @@
return location ? location.column + 1: null;
};
-CallSite.prototype.isNative = function () {
+function CallSiteIsNative() {
var script = %FunctionGetScript(this.fun);
return script ? (script.type == TYPE_NATIVE) : false;
};
-CallSite.prototype.getPosition = function () {
+function CallSiteGetPosition() {
return this.pos;
};
-CallSite.prototype.isConstructor = function () {
+function CallSiteIsConstructor() {
var constructor = this.receiver ? this.receiver.constructor : null;
if (!constructor) {
return false;
@@ -859,6 +890,25 @@
return this.fun === constructor;
};
+SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
+ "getThis", CallSiteGetThis,
+ "getTypeName", CallSiteGetTypeName,
+ "isToplevel", CallSiteIsToplevel,
+ "isEval", CallSiteIsEval,
+ "getEvalOrigin", CallSiteGetEvalOrigin,
+ "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
+ "getFunction", CallSiteGetFunction,
+ "getFunctionName", CallSiteGetFunctionName,
+ "getMethodName", CallSiteGetMethodName,
+ "getFileName", CallSiteGetFileName,
+ "getLineNumber", CallSiteGetLineNumber,
+ "getColumnNumber", CallSiteGetColumnNumber,
+ "isNative", CallSiteIsNative,
+ "getPosition", CallSiteGetPosition,
+ "isConstructor", CallSiteIsConstructor
+));
+
+
function FormatEvalOrigin(script) {
var sourceURL = script.nameOrSourceURL();
if (sourceURL) {
@@ -1000,63 +1050,6 @@
}
}
-function DefineError(f) {
- // Store the error function in both the global object
- // and the runtime object. The function is fetched
- // from the runtime object when throwing errors from
- // within the runtime system to avoid strange side
- // effects when overwriting the error functions from
- // user code.
- var name = f.name;
- %SetProperty(global, name, f, DONT_ENUM);
- this['$' + name] = f;
- // Configure the error function.
- if (name == 'Error') {
- // The prototype of the Error object must itself be an error.
- // However, it can't be an instance of the Error object because
- // it hasn't been properly configured yet. Instead we create a
- // special not-a-true-error-but-close-enough object.
- function ErrorPrototype() {}
- %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
- %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
- %FunctionSetPrototype(f, new ErrorPrototype());
- } else {
- %FunctionSetPrototype(f, new $Error());
- }
- %FunctionSetInstanceClassName(f, 'Error');
- %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
- // The name property on the prototype of error objects is not
- // specified as being read-one and dont-delete. However, allowing
- // overwriting allows leaks of error objects between script blocks
- // in the same context in a browser setting. Therefore we fix the
- // name.
- %SetProperty(f.prototype, "name", name, DONT_ENUM | DONT_DELETE | READ_ONLY);
- %SetCode(f, function(m) {
- if (%_IsConstructCall()) {
- // Define all the expected properties directly on the error
- // object. This avoids going through getters and setters defined
- // on prototype objects.
- %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
- %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
- %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
- if (m === kAddMessageAccessorsMarker) {
- // DefineOneShotAccessor always inserts a message property and
- // ignores setters.
- DefineOneShotAccessor(this, 'message', function (obj) {
- return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
- });
- } else if (!IS_UNDEFINED(m)) {
- %IgnoreAttributesAndSetProperty(this,
- 'message',
- ToString(m),
- DONT_ENUM);
- }
- captureStackTrace(this, f);
- } else {
- return new f(m);
- }
- });
-}
function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit;
@@ -1072,52 +1065,100 @@
});
};
-$Math.__proto__ = global.Object.prototype;
-// DefineError is a native function. Use explicit receiver. Otherwise
-// the receiver will be 'undefined'.
-this.DefineError(function Error() { });
-this.DefineError(function TypeError() { });
-this.DefineError(function RangeError() { });
-this.DefineError(function SyntaxError() { });
-this.DefineError(function ReferenceError() { });
-this.DefineError(function EvalError() { });
-this.DefineError(function URIError() { });
+function SetUpError() {
+ // Define special error type constructors.
+
+ function DefineError(f) {
+ // Store the error function in both the global object
+ // and the runtime object. The function is fetched
+ // from the runtime object when throwing errors from
+ // within the runtime system to avoid strange side
+ // effects when overwriting the error functions from
+ // user code.
+ var name = f.name;
+ %SetProperty(global, name, f, DONT_ENUM);
+ %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ // Configure the error function.
+ if (name == 'Error') {
+ // The prototype of the Error object must itself be an error.
+ // However, it can't be an instance of the Error object because
+ // it hasn't been properly configured yet. Instead we create a
+ // special not-a-true-error-but-close-enough object.
+ function ErrorPrototype() {}
+ %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
+ %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
+ %FunctionSetPrototype(f, new ErrorPrototype());
+ } else {
+ %FunctionSetPrototype(f, new $Error());
+ }
+ %FunctionSetInstanceClassName(f, 'Error');
+ %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
+ // The name property on the prototype of error objects is not
+ // specified as being read-one and dont-delete. However, allowing
+ // overwriting allows leaks of error objects between script blocks
+ // in the same context in a browser setting. Therefore we fix the
+ // name.
+ %SetProperty(f.prototype, "name", name,
+ DONT_ENUM | DONT_DELETE | READ_ONLY) ;
+ %SetCode(f, function(m) {
+ if (%_IsConstructCall()) {
+ // Define all the expected properties directly on the error
+ // object. This avoids going through getters and setters defined
+ // on prototype objects.
+ %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
+ %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
+ %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
+ if (m === kAddMessageAccessorsMarker) {
+ // DefineOneShotAccessor always inserts a message property and
+ // ignores setters.
+ DefineOneShotAccessor(this, 'message', function (obj) {
+ return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
+ });
+ } else if (!IS_UNDEFINED(m)) {
+ %IgnoreAttributesAndSetProperty(this,
+ 'message',
+ ToString(m),
+ DONT_ENUM);
+ }
+ captureStackTrace(this, f);
+ } else {
+ return new f(m);
+ }
+ });
+ }
+
+ DefineError(function Error() { });
+ DefineError(function TypeError() { });
+ DefineError(function RangeError() { });
+ DefineError(function SyntaxError() { });
+ DefineError(function ReferenceError() { });
+ DefineError(function EvalError() { });
+ DefineError(function URIError() { });
+}
+
+SetUpError();
$Error.captureStackTrace = captureStackTrace;
-// Setup extra properties of the Error.prototype object.
-function setErrorMessage() {
- var desc = {value: '',
- enumerable: false,
- configurable: true,
- writable: true };
- DefineOwnProperty($Error.prototype,
- 'message',
- ToPropertyDescriptor(desc),
- true);
-
-}
-
-setErrorMessage();
+%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
// Global list of error objects visited during errorToString. This is
// used to detect cycles in error toString formatting.
-var visited_errors = new $Array();
-var cyclic_error_marker = new $Object();
+const visited_errors = new InternalArray();
+const cyclic_error_marker = new $Object();
-function errorToStringDetectCycle() {
- if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker;
+function errorToStringDetectCycle(error) {
+ if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
try {
- var type = this.type;
- if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) {
- var formatted = FormatMessage(%NewMessageObject(type, this.arguments));
- return this.name + ": " + formatted;
+ var type = error.type;
+ var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
+ if (type && !hasMessage) {
+ var formatted = FormatMessage(%NewMessageObject(type, error.arguments));
+ return error.name + ": " + formatted;
}
- var message = %_CallFunction(this, "message", ObjectHasOwnProperty)
- ? (": " + this.message)
- : "";
- return this.name + message;
+ var message = hasMessage ? (": " + error.message) : "";
+ return error.name + message;
} finally {
visited_errors.length = visited_errors.length - 1;
}
@@ -1133,7 +1174,7 @@
function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
try {
- return %_CallFunction(this, errorToStringDetectCycle);
+ return errorToStringDetectCycle(this);
} catch(e) {
// If this error message was encountered already return the empty
// string for it instead of recursively formatting it.
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index b5ffe73..c4c4fd2 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -83,6 +83,14 @@
// RelocInfo.
void RelocInfo::apply(intptr_t delta) {
+ if (IsCodeTarget(rmode_)) {
+ uint32_t scope1 = (uint32_t) target_address() & ~kImm28Mask;
+ uint32_t scope2 = reinterpret_cast<uint32_t>(pc_) & ~kImm28Mask;
+
+ if (scope1 != scope2) {
+ Assembler::JumpLabelToJumpRegister(pc_);
+ }
+ }
if (IsInternalReference(rmode_)) {
// Absolute code pointer inside code object moves with the code object.
byte* p = reinterpret_cast<byte*>(pc_);
@@ -218,8 +226,9 @@
Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize);
bool patched_return = ((instr0 & kOpcodeMask) == LUI &&
(instr1 & kOpcodeMask) == ORI &&
- (instr2 & kOpcodeMask) == SPECIAL &&
- (instr2 & kFunctionFieldMask) == JALR);
+ ((instr2 & kOpcodeMask) == JAL ||
+ ((instr2 & kOpcodeMask) == SPECIAL &&
+ (instr2 & kFunctionFieldMask) == JALR)));
return patched_return;
}
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index 28ac557..e01a0ca 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -49,11 +49,47 @@
unsigned CpuFeatures::supported_ = 0;
unsigned CpuFeatures::found_by_runtime_probing_ = 0;
+
+// Get the CPU features enabled by the build. For cross compilation the
+// preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
+// can be defined to enable FPU instructions when building the
+// snapshot.
+static uint64_t CpuFeaturesImpliedByCompiler() {
+ uint64_t answer = 0;
+#ifdef CAN_USE_FPU_INSTRUCTIONS
+ answer |= 1u << FPU;
+#endif // def CAN_USE_FPU_INSTRUCTIONS
+
+#ifdef __mips__
+ // If the compiler is allowed to use FPU then we can use FPU too in our code
+ // generation even when generating snapshots. This won't work for cross
+ // compilation.
+#if(defined(__mips_hard_float) && __mips_hard_float != 0)
+ answer |= 1u << FPU;
+#endif // defined(__mips_hard_float) && __mips_hard_float != 0
+#endif // def __mips__
+
+ return answer;
+}
+
+
void CpuFeatures::Probe() {
ASSERT(!initialized_);
#ifdef DEBUG
initialized_ = true;
#endif
+
+ // Get the features implied by the OS and the compiler settings. This is the
+ // minimal set of features which is also allowed for generated code in the
+ // snapshot.
+ supported_ |= OS::CpuFeaturesImpliedByPlatform();
+ supported_ |= CpuFeaturesImpliedByCompiler();
+
+ if (Serializer::enabled()) {
+ // No probing for features if we might serialize (generate snapshot).
+ return;
+ }
+
// If the compiler is allowed to use fpu then we can use fpu too in our
// code generation.
#if !defined(__mips__)
@@ -62,11 +98,7 @@
supported_ |= 1u << FPU;
}
#else
- if (Serializer::enabled()) {
- supported_ |= OS::CpuFeaturesImpliedByPlatform();
- return; // No features if we might serialize.
- }
-
+ // Probe for additional features not already known to be available.
if (OS::MipsCpuHasFeature(FPU)) {
// This implementation also sets the FPU flags if
// runtime detection of FPU returns true.
@@ -140,7 +172,8 @@
// -----------------------------------------------------------------------------
// Implementation of RelocInfo.
-const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
+const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
+ 1 << RelocInfo::INTERNAL_REFERENCE;
bool RelocInfo::IsCodedSpecially() {
@@ -514,6 +547,19 @@
}
+bool Assembler::IsJal(Instr instr) {
+ return GetOpcodeField(instr) == JAL;
+}
+
+bool Assembler::IsJr(Instr instr) {
+ return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
+}
+
+bool Assembler::IsJalr(Instr instr) {
+ return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
+}
+
+
bool Assembler::IsLui(Instr instr) {
uint32_t opcode = GetOpcodeField(instr);
// Checks if the instruction is a load upper immediate.
@@ -907,7 +953,7 @@
void Assembler::GenInstrJump(Opcode opcode,
- uint32_t address) {
+ uint32_t address) {
BlockTrampolinePoolScope block_trampoline_pool(this);
ASSERT(is_uint26(address));
Instr instr = opcode | address;
@@ -1080,7 +1126,12 @@
void Assembler::j(int32_t target) {
- ASSERT(is_uint28(target) && ((target & 3) == 0));
+#if DEBUG
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+ ASSERT(in_range && ((target & 3) == 0));
+#endif
GenInstrJump(J, target >> 2);
}
@@ -1096,8 +1147,13 @@
void Assembler::jal(int32_t target) {
+#ifdef DEBUG
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+ ASSERT(in_range && ((target & 3) == 0));
+#endif
positions_recorder()->WriteRecordedPositions();
- ASSERT(is_uint28(target) && ((target & 3) == 0));
GenInstrJump(JAL, target >> 2);
}
@@ -1110,6 +1166,32 @@
}
+void Assembler::j_or_jr(int32_t target, Register rs) {
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+
+ if (in_range) {
+ j(target);
+ } else {
+ jr(t9);
+ }
+}
+
+
+void Assembler::jal_or_jalr(int32_t target, Register rs) {
+ // Get pc of delay slot.
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
+ bool in_range = ((uint32_t)(ipc^target) >> (kImm26Bits+kImmFieldShift)) == 0;
+
+ if (in_range) {
+ jal(target);
+ } else {
+ jalr(t9);
+ }
+}
+
+
//-------Data-processing-instructions---------
// Arithmetic.
@@ -1582,6 +1664,13 @@
GenInstrRegister(COP1, CFC1, rt, fs);
}
+void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
+ uint64_t i;
+ memcpy(&i, &d, 8);
+
+ *lo = i & 0xffffffff;
+ *hi = i >> 32;
+}
// Arithmetic.
@@ -1940,10 +2029,15 @@
}
if (rinfo.rmode() != RelocInfo::NONE) {
// Don't record external references unless the heap will be serialized.
- if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
- !Serializer::enabled() &&
- !FLAG_debug_code) {
- return;
+ if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+#ifdef DEBUG
+ if (!Serializer::enabled()) {
+ Serializer::TooLateToEnableNow();
+ }
+#endif
+ if (!Serializer::enabled() && !emit_debug_code()) {
+ return;
+ }
}
ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
@@ -2038,30 +2132,142 @@
}
+// On Mips, a target address is stored in a lui/ori instruction pair, each
+// of which load 16 bits of the 32-bit address to a register.
+// Patching the address must replace both instr, and flush the i-cache.
+//
+// There is an optimization below, which emits a nop when the address
+// fits in just 16 bits. This is unlikely to help, and should be benchmarked,
+// and possibly removed.
void Assembler::set_target_address_at(Address pc, Address target) {
- // On MIPS we patch the address into lui/ori instruction pair.
-
- // First check we have an li (lui/ori pair).
Instr instr2 = instr_at(pc + kInstrSize);
-#ifdef DEBUG
- Instr instr1 = instr_at(pc);
-
- // Check we have indeed the result from a li with MustUseReg true.
- CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
-#endif
-
uint32_t rt_code = GetRtField(instr2);
uint32_t* p = reinterpret_cast<uint32_t*>(pc);
uint32_t itarget = reinterpret_cast<uint32_t>(target);
- // lui rt, high-16.
- // ori rt rt, low-16.
+#ifdef DEBUG
+ // Check we have the result from a li macro-instruction, using instr pair.
+ Instr instr1 = instr_at(pc);
+ CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
+#endif
+
+ // Must use 2 instructions to insure patchable code => just use lui and ori.
+ // lui rt, upper-16.
+ // ori rt rt, lower-16.
*p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
*(p+1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
- CPU::FlushICache(pc, 2 * sizeof(int32_t));
+ // The following code is an optimization for the common case of Call()
+ // or Jump() which is load to register, and jump through register:
+ // li(t9, address); jalr(t9) (or jr(t9)).
+ // If the destination address is in the same 256 MB page as the call, it
+ // is faster to do a direct jal, or j, rather than jump thru register, since
+ // that lets the cpu pipeline prefetch the target address. However each
+ // time the address above is patched, we have to patch the direct jal/j
+ // instruction, as well as possibly revert to jalr/jr if we now cross a
+ // 256 MB page. Note that with the jal/j instructions, we do not need to
+ // load the register, but that code is left, since it makes it easy to
+ // revert this process. A further optimization could try replacing the
+ // li sequence with nops.
+ // This optimization can only be applied if the rt-code from instr2 is the
+ // register used for the jalr/jr. Finally, we have to skip 'jr ra', which is
+ // mips return. Occasionally this lands after an li().
+
+ Instr instr3 = instr_at(pc + 2 * kInstrSize);
+ uint32_t ipc = reinterpret_cast<uint32_t>(pc + 3 * kInstrSize);
+ bool in_range =
+ ((uint32_t)(ipc ^ itarget) >> (kImm26Bits + kImmFieldShift)) == 0;
+ uint32_t target_field = (uint32_t)(itarget & kJumpAddrMask) >> kImmFieldShift;
+ bool patched_jump = false;
+
+#ifndef ALLOW_JAL_IN_BOUNDARY_REGION
+ // This is a workaround to the 24k core E156 bug (affect some 34k cores also).
+ // Since the excluded space is only 64KB out of 256MB (0.02 %), we will just
+ // apply this workaround for all cores so we don't have to identify the core.
+ if (in_range) {
+ // The 24k core E156 bug has some very specific requirements, we only check
+ // the most simple one: if the address of the delay slot instruction is in
+ // the first or last 32 KB of the 256 MB segment.
+ uint32_t segment_mask = ((256 * MB) - 1) ^ ((32 * KB) - 1);
+ uint32_t ipc_segment_addr = ipc & segment_mask;
+ if (ipc_segment_addr == 0 || ipc_segment_addr == segment_mask)
+ in_range = false;
+ }
+#endif
+
+ if (IsJalr(instr3)) {
+ // Try to convert JALR to JAL.
+ if (in_range && GetRt(instr2) == GetRs(instr3)) {
+ *(p+2) = JAL | target_field;
+ patched_jump = true;
+ }
+ } else if (IsJr(instr3)) {
+ // Try to convert JR to J, skip returns (jr ra).
+ bool is_ret = static_cast<int>(GetRs(instr3)) == ra.code();
+ if (in_range && !is_ret && GetRt(instr2) == GetRs(instr3)) {
+ *(p+2) = J | target_field;
+ patched_jump = true;
+ }
+ } else if (IsJal(instr3)) {
+ if (in_range) {
+ // We are patching an already converted JAL.
+ *(p+2) = JAL | target_field;
+ } else {
+ // Patch JAL, but out of range, revert to JALR.
+ // JALR rs reg is the rt reg specified in the ORI instruction.
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
+ *(p+2) = SPECIAL | rs_field | rd_field | JALR;
+ }
+ patched_jump = true;
+ } else if (IsJ(instr3)) {
+ if (in_range) {
+ // We are patching an already converted J (jump).
+ *(p+2) = J | target_field;
+ } else {
+ // Trying patch J, but out of range, just go back to JR.
+ // JR 'rs' reg is the 'rt' reg specified in the ORI instruction (instr2).
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ *(p+2) = SPECIAL | rs_field | JR;
+ }
+ patched_jump = true;
+ }
+
+ CPU::FlushICache(pc, (patched_jump ? 3 : 2) * sizeof(int32_t));
}
+void Assembler::JumpLabelToJumpRegister(Address pc) {
+ // Address pc points to lui/ori instructions.
+ // Jump to label may follow at pc + 2 * kInstrSize.
+ uint32_t* p = reinterpret_cast<uint32_t*>(pc);
+#ifdef DEBUG
+ Instr instr1 = instr_at(pc);
+#endif
+ Instr instr2 = instr_at(pc + 1 * kInstrSize);
+ Instr instr3 = instr_at(pc + 2 * kInstrSize);
+ bool patched = false;
+
+ if (IsJal(instr3)) {
+ ASSERT(GetOpcodeField(instr1) == LUI);
+ ASSERT(GetOpcodeField(instr2) == ORI);
+
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ uint32_t rd_field = ra.code() << kRdShift; // Return-address (ra) reg.
+ *(p+2) = SPECIAL | rs_field | rd_field | JALR;
+ patched = true;
+ } else if (IsJ(instr3)) {
+ ASSERT(GetOpcodeField(instr1) == LUI);
+ ASSERT(GetOpcodeField(instr2) == ORI);
+
+ uint32_t rs_field = GetRt(instr2) << kRsShift;
+ *(p+2) = SPECIAL | rs_field | JR;
+ patched = true;
+ }
+
+ if (patched) {
+ CPU::FlushICache(pc+2, sizeof(Address));
+ }
+}
} } // namespace v8::internal
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index e5077be..38e9537 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -168,24 +168,36 @@
// Coprocessor register.
struct FPURegister {
static const int kNumRegisters = v8::internal::kNumFPURegisters;
- // f0 has been excluded from allocation. This is following ia32
- // where xmm0 is excluded.
- static const int kNumAllocatableRegisters = 15;
+
+ // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
+ // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
+ // number of Double regs (64-bit regs, or FPU-reg-pairs).
+
+ // A few double registers are reserved: one as a scratch register and one to
+ // hold 0.0.
+ // f28: 0.0
+ // f30: scratch register.
+ static const int kNumReservedRegisters = 2;
+ static const int kNumAllocatableRegisters = kNumRegisters / 2 -
+ kNumReservedRegisters;
+
static int ToAllocationIndex(FPURegister reg) {
- ASSERT(reg.code() != 0);
ASSERT(reg.code() % 2 == 0);
- return (reg.code() / 2) - 1;
+ ASSERT(reg.code() / 2 < kNumAllocatableRegisters);
+ ASSERT(reg.is_valid());
+ return (reg.code() / 2);
}
static FPURegister FromAllocationIndex(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
- return from_code((index + 1) * 2);
+ return from_code(index * 2);
}
static const char* AllocationIndexToString(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
const char* const names[] = {
+ "f0",
"f2",
"f4",
"f6",
@@ -198,9 +210,7 @@
"f20",
"f22",
"f24",
- "f26",
- "f28",
- "f30"
+ "f26"
};
return names[index];
}
@@ -212,6 +222,23 @@
bool is_valid() const { return 0 <= code_ && code_ < kNumFPURegisters ; }
bool is(FPURegister creg) const { return code_ == creg.code_; }
+ FPURegister low() const {
+ // Find low reg of a Double-reg pair, which is the reg itself.
+ ASSERT(code_ % 2 == 0); // Specified Double reg must be even.
+ FPURegister reg;
+ reg.code_ = code_;
+ ASSERT(reg.is_valid());
+ return reg;
+ }
+ FPURegister high() const {
+ // Find high reg of a Doubel-reg pair, which is reg + 1.
+ ASSERT(code_ % 2 == 0); // Specified Double reg must be even.
+ FPURegister reg;
+ reg.code_ = code_ + 1;
+ ASSERT(reg.is_valid());
+ return reg;
+ }
+
int code() const {
ASSERT(is_valid());
return code_;
@@ -228,9 +255,19 @@
int code_;
};
-typedef FPURegister DoubleRegister;
+// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
+// 32-bit registers, f0 through f31. When used as 'double' they are used
+// in pairs, starting with the even numbered register. So a double operation
+// on f0 really uses f0 and f1.
+// (Modern mips hardware also supports 32 64-bit registers, via setting
+// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
+// but it is not in common use. Someday we will want to support this in v8.)
-const FPURegister no_creg = { -1 };
+// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
+typedef FPURegister DoubleRegister;
+typedef FPURegister FloatRegister;
+
+const FPURegister no_freg = { -1 };
const FPURegister f0 = { 0 }; // Return value in hard float mode.
const FPURegister f1 = { 1 };
@@ -265,6 +302,8 @@
const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 };
+const FPURegister kDoubleRegZero = f28;
+
// FPU (coprocessor 1) control registers.
// Currently only FCSR (#31) is implemented.
struct FPUControlRegister {
@@ -331,6 +370,10 @@
explicit MemOperand(Register rn, int32_t offset = 0);
int32_t offset() const { return offset_; }
+ bool OffsetIsInt16Encodable() const {
+ return is_int16(offset_);
+ }
+
private:
int32_t offset_;
@@ -504,6 +547,8 @@
static Address target_address_at(Address pc);
static void set_target_address_at(Address pc, Address target);
+ static void JumpLabelToJumpRegister(Address pc);
+
// This sets the branch destination (which gets loaded at the call address).
// This is for calls and branches within generated code.
inline static void set_target_at(Address instruction_payload,
@@ -534,9 +579,13 @@
static const int kExternalTargetSize = 0 * kInstrSize;
// Number of consecutive instructions used to store 32bit constant.
- // Used in RelocInfo::target_address_address() function to tell serializer
- // address of the instruction that follows LUI/ORI instruction pair.
- static const int kInstructionsFor32BitConstant = 2;
+ // Before jump-optimizations, this constant was used in
+ // RelocInfo::target_address_address() function to tell serializer address of
+ // the instruction that follows LUI/ORI instruction pair. Now, with new jump
+ // optimization, where jump-through-register instruction that usually
+ // follows LUI/ORI pair is substituted with J/JAL, this constant equals
+ // to 3 instructions (LUI+ORI+J/JAL/JR/JALR).
+ static const int kInstructionsFor32BitConstant = 3;
// Distance between the instruction referring to the address of the call
// target and the return address.
@@ -623,6 +672,8 @@
void jal(int32_t target);
void jalr(Register rs, Register rd = ra);
void jr(Register target);
+ void j_or_jr(int32_t target, Register rs);
+ void jal_or_jalr(int32_t target, Register rs);
//-------Data-processing-instructions---------
@@ -892,6 +943,10 @@
static bool IsLui(Instr instr);
static bool IsOri(Instr instr);
+ static bool IsJal(Instr instr);
+ static bool IsJr(Instr instr);
+ static bool IsJalr(Instr instr);
+
static bool IsNop(Instr instr, unsigned int type);
static bool IsPop(Instr instr);
static bool IsPush(Instr instr);
@@ -976,6 +1031,8 @@
return internal_trampoline_exception_;
}
+ void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi);
+
bool is_trampoline_emitted() const {
return trampoline_emitted_;
}
@@ -1159,6 +1216,7 @@
}
return trampoline_slot;
}
+
private:
int start_;
int end_;
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 1555653..d772304 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -210,7 +210,7 @@
// Allocate the JSArray object together with space for a FixedArray with the
// requested number of elements.
__ bind(¬_empty);
- ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ li(elements_array_end,
(JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize);
__ sra(scratch1, array_size, kSmiTagSize);
@@ -261,7 +261,7 @@
// Length of the FixedArray is the number of pre-allocated elements if
// the actual JSArray has length 0 and the size of the JSArray for non-empty
// JSArrays. The length of a FixedArray is stored as a smi.
- ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTag == 0);
__ li(at, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
__ movz(array_size, at, array_size);
@@ -273,7 +273,7 @@
// result: JSObject
// elements_array_storage: elements array element storage
// array_size: smi-tagged size of elements array
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(elements_array_end, array_size, kPointerSizeLog2 - kSmiTagSize);
__ Addu(elements_array_end, elements_array_storage, elements_array_end);
@@ -336,14 +336,14 @@
__ bind(&argc_one_or_more);
__ Branch(&argc_two_or_more, ne, a0, Operand(1));
- ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTag == 0);
__ lw(a2, MemOperand(sp)); // Get the argument from the stack.
__ And(a3, a2, Operand(kIntptrSignBit | kSmiTagMask));
__ Branch(call_generic_code, eq, a3, Operand(zero_reg));
// Handle construction of an empty array of a certain size. Bail out if size
// is too large to actually allocate an elements array.
- ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTag == 0);
__ Branch(call_generic_code, Ugreater_equal, a2,
Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
@@ -576,7 +576,7 @@
// Is it a String?
__ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
__ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
- ASSERT(kNotStringTag != 0);
+ STATIC_ASSERT(kNotStringTag != 0);
__ And(t0, a3, Operand(kIsNotStringMask));
__ Branch(&convert_argument, ne, t0, Operand(zero_reg));
__ mov(argument, a0);
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 9385f2f..521b8e5 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -3538,7 +3538,7 @@
const int kNumInstructionsToJump = 6;
masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize);
masm->sw(ra, MemOperand(sp)); // This spot was reserved in EnterExitFrame.
- masm->Subu(sp, sp, StandardFrameConstants::kCArgsSlotsSize);
+ masm->Subu(sp, sp, kCArgsSlotsSize);
// Stack is still aligned.
// Call the C routine.
@@ -3551,7 +3551,7 @@
}
// Restore stack (remove arg slots).
- __ Addu(sp, sp, StandardFrameConstants::kCArgsSlotsSize);
+ __ Addu(sp, sp, kCArgsSlotsSize);
if (always_allocate) {
// It's okay to clobber a2 and a3 here. v0 & v1 contain result.
@@ -3591,7 +3591,7 @@
__ li(t0,
Operand(ExternalReference::the_hole_value_location(masm->isolate())));
__ lw(a3, MemOperand(t0));
- __ li(t0, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ lw(v0, MemOperand(t0));
__ sw(a3, MemOperand(t0));
@@ -3695,16 +3695,26 @@
// Save callee saved registers on the stack.
__ MultiPush(kCalleeSaved | ra.bit());
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ // Save callee-saved FPU registers.
+ __ MultiPushFPU(kCalleeSavedFPU);
+ }
+
// Load argv in s0 register.
- __ lw(s0, MemOperand(sp, (kNumCalleeSaved + 1) * kPointerSize +
- StandardFrameConstants::kCArgsSlotsSize));
+ int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
+ if (CpuFeatures::IsSupported(FPU)) {
+ offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
+ }
+
+ __ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
// We build an EntryFrame.
__ li(t3, Operand(-1)); // Push a bad frame pointer to fail if it is used.
int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
__ li(t2, Operand(Smi::FromInt(marker)));
__ li(t1, Operand(Smi::FromInt(marker)));
- __ li(t0, Operand(ExternalReference(Isolate::k_c_entry_fp_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
masm->isolate())));
__ lw(t0, MemOperand(t0));
__ Push(t3, t2, t1, t0);
@@ -3729,7 +3739,7 @@
// If this is the outermost JS call, set js_entry_sp value.
Label non_outermost_js;
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address,
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress,
masm->isolate());
__ li(t1, Operand(ExternalReference(js_entry_sp)));
__ lw(t2, MemOperand(t1));
@@ -3752,7 +3762,7 @@
// exception field in the JSEnv and return a failure sentinel.
// Coming in here the fp will be invalid because the PushTryHandler below
// sets it to 0 to signal the existence of the JSEntry frame.
- __ li(t0, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ sw(v0, MemOperand(t0)); // We come back from 'invoke'. result is in v0.
__ li(v0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
@@ -3771,7 +3781,7 @@
__ li(t0,
Operand(ExternalReference::the_hole_value_location(masm->isolate())));
__ lw(t1, MemOperand(t0));
- __ li(t0, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ sw(t1, MemOperand(t0));
@@ -3822,13 +3832,19 @@
// Restore the top frame descriptors from the stack.
__ pop(t1);
- __ li(t0, Operand(ExternalReference(Isolate::k_c_entry_fp_address,
+ __ li(t0, Operand(ExternalReference(Isolate::kCEntryFPAddress,
masm->isolate())));
__ sw(t1, MemOperand(t0));
// Reset the stack to the callee saved registers.
__ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset);
+ if (CpuFeatures::IsSupported(FPU)) {
+ CpuFeatures::Scope scope(FPU);
+ // Restore callee-saved fpu registers.
+ __ MultiPopFPU(kCalleeSavedFPU);
+ }
+
// Restore callee saved registers from the stack.
__ MultiPop(kCalleeSaved | ra.bit());
// Return.
@@ -4652,7 +4668,7 @@
// frame. Therefore we have to use fp, which points exactly to two pointer
// sizes below the previous sp. (Because creating a new stack frame pushes
// the previous fp onto the stack and moves up sp by 2 * kPointerSize.)
- __ lw(a0, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
+ __ lw(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
// If slice offset is not 0, load the length from the original sliced string.
// Argument 4, a3: End of string data
// Argument 3, a2: Start of string data
@@ -4662,7 +4678,7 @@
__ sllv(t1, a1, a3);
__ addu(a2, t0, t1);
- __ lw(t2, FieldMemOperand(a0, String::kLengthOffset));
+ __ lw(t2, FieldMemOperand(subject, String::kLengthOffset));
__ sra(t2, t2, kSmiTagSize);
__ sllv(t1, t2, a3);
__ addu(a3, t0, t1);
@@ -4670,7 +4686,7 @@
// Already there
// Argument 1 (a0): Subject string.
- // Already there
+ __ mov(a0, subject);
// Locate the code entry and call it.
__ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
@@ -4688,13 +4704,13 @@
Label success;
__ Branch(&success, eq,
- subject, Operand(NativeRegExpMacroAssembler::SUCCESS));
+ v0, Operand(NativeRegExpMacroAssembler::SUCCESS));
Label failure;
__ Branch(&failure, eq,
- subject, Operand(NativeRegExpMacroAssembler::FAILURE));
+ v0, Operand(NativeRegExpMacroAssembler::FAILURE));
// If not exception it can only be retry. Handle that in the runtime system.
__ Branch(&runtime, ne,
- subject, Operand(NativeRegExpMacroAssembler::EXCEPTION));
+ v0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
// Result must now be exception. If there is no pending exception already a
// stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system.
@@ -4702,19 +4718,19 @@
__ li(a1, Operand(
ExternalReference::the_hole_value_location(masm->isolate())));
__ lw(a1, MemOperand(a1, 0));
- __ li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
masm->isolate())));
__ lw(v0, MemOperand(a2, 0));
- __ Branch(&runtime, eq, subject, Operand(a1));
+ __ Branch(&runtime, eq, v0, Operand(a1));
__ sw(a1, MemOperand(a2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
Label termination_exception;
- __ Branch(&termination_exception, eq, subject, Operand(a0));
+ __ Branch(&termination_exception, eq, v0, Operand(a0));
- __ Throw(subject); // Expects thrown value in v0.
+ __ Throw(v0); // Expects thrown value in v0.
__ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, v0); // Expects thrown value in v0.
@@ -5062,7 +5078,8 @@
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ And(t0, result_, Operand(kStringEncodingMask));
__ Branch(&ascii_string, ne, t0, Operand(zero_reg));
@@ -5625,11 +5642,6 @@
Register to = t2;
Register from = t3;
- if (FLAG_string_slices) {
- __ nop(); // Jumping as first instruction would crash the code generation.
- __ jmp(&sub_string_runtime);
- }
-
// Check bounds and smi-ness.
__ lw(to, MemOperand(sp, kToOffset));
__ lw(from, MemOperand(sp, kFromOffset));
@@ -5653,7 +5665,8 @@
// Special handling of sub-strings of length 1 and 2. One character strings
// are handled in the runtime system (looked up in the single character
- // cache). Two character strings are looked for in the symbol cache.
+ // cache). Two character strings are looked for in the symbol cache in
+ // generated code.
__ Branch(&sub_string_runtime, lt, a2, Operand(2));
// Both to and from are smis.
@@ -5665,19 +5678,32 @@
// t5: to index (untagged smi)
// Make sure first argument is a sequential (or flat) string.
- __ lw(t1, MemOperand(sp, kStringOffset));
- __ Branch(&sub_string_runtime, eq, t1, Operand(kSmiTagMask));
+ __ lw(v0, MemOperand(sp, kStringOffset));
+ __ Branch(&sub_string_runtime, eq, v0, Operand(kSmiTagMask));
- __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
+ __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
- __ And(t4, a1, Operand(kIsNotStringMask));
+ __ And(t4, v0, Operand(kIsNotStringMask));
__ Branch(&sub_string_runtime, ne, t4, Operand(zero_reg));
+ // Short-cut for the case of trivial substring.
+ Label return_v0;
+ // v0: original string
+ // a2: result string length
+ __ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
+ __ sra(t0, t0, 1);
+ __ Branch(&return_v0, eq, a2, Operand(t0));
+
+ Label create_slice;
+ if (FLAG_string_slices) {
+ __ Branch(&create_slice, ge, a2, Operand(SlicedString::kMinLength));
+ }
+
+ // v0: original string
// a1: instance type
// a2: result string length
// a3: from index (untagged smi)
- // t1: string
// t2: (a.k.a. to): to (smi)
// t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi)
@@ -5686,8 +5712,9 @@
__ And(t0, a1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag < kConsStringTag);
STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+ STATIC_ASSERT(kConsStringTag < kSlicedStringTag);
- // External strings go to runtime.
+ // Slices and external strings go to runtime.
__ Branch(&sub_string_runtime, gt, t0, Operand(kConsStringTag));
// Sequential strings are handled directly.
@@ -5696,32 +5723,32 @@
// Cons string. Try to recurse (once) on the first substring.
// (This adds a little more generality than necessary to handle flattened
// cons strings, but not much).
- __ lw(t1, FieldMemOperand(t1, ConsString::kFirstOffset));
- __ lw(t0, FieldMemOperand(t1, HeapObject::kMapOffset));
+ __ lw(v0, FieldMemOperand(v0, ConsString::kFirstOffset));
+ __ lw(t0, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(a1, FieldMemOperand(t0, Map::kInstanceTypeOffset));
STATIC_ASSERT(kSeqStringTag == 0);
- // Cons and External strings go to runtime.
+ // Cons, slices and external strings go to runtime.
__ Branch(&sub_string_runtime, ne, a1, Operand(kStringRepresentationMask));
// Definitly a sequential string.
__ bind(&seq_string);
+ // v0: original string
// a1: instance type
// a2: result string length
// a3: from index (untagged smi)
- // t1: string
// t2: (a.k.a. to): to (smi)
// t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi)
- __ lw(t0, FieldMemOperand(t1, String::kLengthOffset));
+ __ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
__ Branch(&sub_string_runtime, lt, t0, Operand(to)); // Fail if to > length.
to = no_reg;
+ // v0: original string or left hand side of the original cons string.
// a1: instance type
// a2: result string length
// a3: from index (untagged smi)
- // t1: string
// t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi)
@@ -5737,84 +5764,147 @@
// Sub string of length 2 requested.
// Get the two characters forming the sub string.
- __ Addu(t1, t1, Operand(a3));
- __ lbu(a3, FieldMemOperand(t1, SeqAsciiString::kHeaderSize));
- __ lbu(t0, FieldMemOperand(t1, SeqAsciiString::kHeaderSize + 1));
+ __ Addu(v0, v0, Operand(a3));
+ __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
+ __ lbu(t0, FieldMemOperand(v0, SeqAsciiString::kHeaderSize + 1));
// Try to lookup two character string in symbol table.
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string);
Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
- __ Addu(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
-
+ __ jmp(&return_v0);
// a2: result string length.
// a3: two characters combined into halfword in little endian byte order.
__ bind(&make_two_character_string);
__ AllocateAsciiString(v0, a2, t0, t1, t4, &sub_string_runtime);
__ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
- __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
- __ Addu(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_v0);
__ bind(&result_longer_than_two);
+ // Locate 'from' character of string.
+ __ Addu(t1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ __ sra(t4, from, 1);
+ __ Addu(t1, t1, t4);
+
// Allocate the result.
__ AllocateAsciiString(v0, a2, t4, t0, a1, &sub_string_runtime);
- // v0: result string.
- // a2: result string length.
+ // v0: result string
+ // a2: result string length
// a3: from index (untagged smi)
- // t1: string.
+ // t1: first character of substring to copy
// t3: (a.k.a. from): from offset (smi)
// Locate first character of result.
__ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ Addu(t1, t1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- __ Addu(t1, t1, Operand(a3));
- // v0: result string.
- // a1: first character of result string.
- // a2: result string length.
- // t1: first character of sub string to copy.
+ // v0: result string
+ // a1: first character of result string
+ // a2: result string length
+ // t1: first character of substring to copy
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED);
- __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
- __ Addu(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ jmp(&return_v0);
__ bind(&non_ascii_flat);
- // a2: result string length.
- // t1: string.
+ // a2: result string length
+ // t1: string
// t3: (a.k.a. from): from offset (smi)
// Check for flat two byte string.
+ // Locate 'from' character of string.
+ __ Addu(t1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+ // As "from" is a smi it is 2 times the value which matches the size of a two
+ // byte character.
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ __ Addu(t1, t1, Operand(from));
+
// Allocate the result.
__ AllocateTwoByteString(v0, a2, a1, a3, t0, &sub_string_runtime);
- // v0: result string.
- // a2: result string length.
- // t1: string.
+ // v0: result string
+ // a2: result string length
+ // t1: first character of substring to copy
// Locate first character of result.
__ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // Locate 'from' character of string.
- __ Addu(t1, t1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // As "from" is a smi it is 2 times the value which matches the size of a two
- // byte character.
- __ Addu(t1, t1, Operand(from));
+
from = no_reg;
// v0: result string.
// a1: first character of result.
// a2: result length.
- // t1: first character of string to copy.
+ // t1: first character of substring to copy.
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED);
+ __ jmp(&return_v0);
+
+ if (FLAG_string_slices) {
+ __ bind(&create_slice);
+ // v0: original string
+ // a1: instance type
+ // a2: length
+ // a3: from index (untagged smi)
+ // t2 (a.k.a. to): to (smi)
+ // t3 (a.k.a. from): from offset (smi)
+ Label allocate_slice, sliced_string, seq_string;
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ And(t4, a1, Operand(kStringRepresentationMask));
+ __ Branch(&seq_string, eq, t4, Operand(zero_reg));
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+ STATIC_ASSERT(kIsIndirectStringMask != 0);
+ __ And(t4, a1, Operand(kIsIndirectStringMask));
+ // External string. Jump to runtime.
+ __ Branch(&sub_string_runtime, eq, t4, Operand(zero_reg));
+
+ __ And(t4, a1, Operand(kSlicedNotConsMask));
+ __ Branch(&sliced_string, ne, t4, Operand(zero_reg));
+ // Cons string. Check whether it is flat, then fetch first part.
+ __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset));
+ __ LoadRoot(t5, Heap::kEmptyStringRootIndex);
+ __ Branch(&sub_string_runtime, ne, t1, Operand(t5));
+ __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&sliced_string);
+ // Sliced string. Fetch parent and correct start index by offset.
+ __ lw(t1, FieldMemOperand(v0, SlicedString::kOffsetOffset));
+ __ addu(t3, t3, t1);
+ __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
+ __ jmp(&allocate_slice);
+
+ __ bind(&seq_string);
+ // Sequential string. Just move string to the right register.
+ __ mov(t1, v0);
+
+ __ bind(&allocate_slice);
+ // a1: instance type of original string
+ // a2: length
+ // t1: underlying subject string
+ // t3 (a.k.a. from): from offset (smi)
+ // Allocate new sliced string. At this point we do not reload the instance
+ // type including the string encoding because we simply rely on the info
+ // provided by the original string. It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of
+ // the newly created string's parent anyways due to externalized strings.
+ Label two_byte_slice, set_slice_header;
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ And(t4, a1, Operand(kStringEncodingMask));
+ __ Branch(&two_byte_slice, eq, t4, Operand(zero_reg));
+ __ AllocateAsciiSlicedString(v0, a2, a3, t0, &sub_string_runtime);
+ __ jmp(&set_slice_header);
+ __ bind(&two_byte_slice);
+ __ AllocateTwoByteSlicedString(v0, a2, a3, t0, &sub_string_runtime);
+ __ bind(&set_slice_header);
+ __ sw(t3, FieldMemOperand(v0, SlicedString::kOffsetOffset));
+ __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
+ }
+
+ __ bind(&return_v0);
__ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
__ Addu(sp, sp, Operand(3 * kPointerSize));
__ Ret();
diff --git a/src/mips/constants-mips.cc b/src/mips/constants-mips.cc
index 96a2333..d0a7af5 100644
--- a/src/mips/constants-mips.cc
+++ b/src/mips/constants-mips.cc
@@ -191,6 +191,7 @@
const int op = OpcodeFieldRaw();
switch (op) {
case JAL:
+ return true;
case REGIMM:
switch (RtFieldRaw()) {
case BGEZAL:
@@ -272,7 +273,7 @@
case MOVCI:
return kRegisterType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
break;
case SPECIAL2:
@@ -281,7 +282,7 @@
case CLZ:
return kRegisterType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
break;
case SPECIAL3:
@@ -290,7 +291,7 @@
case EXT:
return kRegisterType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
break;
case COP1: // Coprocessor instructions.
@@ -341,7 +342,7 @@
case JAL:
return kJumpType;
default:
- UNREACHABLE();
+ return kUnsupported;
};
return kUnsupported;
}
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index 6bf2570..d76ae59 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -204,6 +204,10 @@
static const int kImm28Shift = 0;
static const int kImm28Bits = 28;
+// In branches and jumps immediate fields point to words, not bytes,
+// and are therefore shifted by 2.
+static const int kImmFieldShift = 2;
+
static const int kFsShift = 11;
static const int kFsBits = 5;
static const int kFtShift = 16;
@@ -233,7 +237,7 @@
static const int kHiMask = 0xffff << 16;
static const int kLoMask = 0xffff;
static const int kSignMask = 0x80000000;
-
+static const int kJumpAddrMask = (1 << (kImm26Bits + kImmFieldShift)) - 1;
// ----- MIPS Opcodes and Function Fields.
// We use this presentation to stay close to the table representation in
@@ -290,12 +294,12 @@
enum SecondaryField {
// SPECIAL Encoding of Function Field.
SLL = ((0 << 3) + 0),
+ MOVCI = ((0 << 3) + 1),
SRL = ((0 << 3) + 2),
SRA = ((0 << 3) + 3),
SLLV = ((0 << 3) + 4),
SRLV = ((0 << 3) + 6),
SRAV = ((0 << 3) + 7),
- MOVCI = ((0 << 3) + 1),
JR = ((1 << 3) + 0),
JALR = ((1 << 3) + 1),
@@ -498,14 +502,38 @@
// ----- Coprocessor conditions.
enum FPUCondition {
- F, // False.
- UN, // Unordered.
- EQ, // Equal.
- UEQ, // Unordered or Equal.
- OLT, // Ordered or Less Than.
- ULT, // Unordered or Less Than.
- OLE, // Ordered or Less Than or Equal.
- ULE // Unordered or Less Than or Equal.
+ kNoFPUCondition = -1,
+
+ F = 0, // False.
+ UN = 1, // Unordered.
+ EQ = 2, // Equal.
+ UEQ = 3, // Unordered or Equal.
+ OLT = 4, // Ordered or Less Than.
+ ULT = 5, // Unordered or Less Than.
+ OLE = 6, // Ordered or Less Than or Equal.
+ ULE = 7 // Unordered or Less Than or Equal.
+};
+
+
+// FPU rounding modes.
+enum FPURoundingMode {
+ RN = 0 << 0, // Round to Nearest.
+ RZ = 1 << 0, // Round towards zero.
+ RP = 2 << 0, // Round towards Plus Infinity.
+ RM = 3 << 0, // Round towards Minus Infinity.
+
+ // Aliases.
+ kRoundToNearest = RN,
+ kRoundToZero = RZ,
+ kRoundToPlusInf = RP,
+ kRoundToMinusInf = RM
+};
+
+static const uint32_t kFPURoundingModeMask = 3 << 0;
+
+enum CheckForInexactConversion {
+ kCheckForInexactConversion,
+ kDontCheckForInexactConversion
};
@@ -716,7 +744,7 @@
inline int32_t Imm26Value() const {
ASSERT(InstructionType() == kJumpType);
- return Bits(kImm16Shift + kImm26Bits - 1, kImm26Shift);
+ return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
}
// Say if the instruction should not be used in a branch delay slot.
@@ -743,11 +771,9 @@
// -----------------------------------------------------------------------------
// MIPS assembly various constants.
-
-static const int kArgsSlotsSize = 4 * Instruction::kInstrSize;
-static const int kArgsSlotsNum = 4;
// C/C++ argument slots size.
-static const int kCArgsSlotsSize = 4 * Instruction::kInstrSize;
+static const int kCArgSlotCount = 4;
+static const int kCArgsSlotsSize = kCArgSlotCount * Instruction::kInstrSize;
// JS argument slots size.
static const int kJSArgsSlotsSize = 0 * Instruction::kInstrSize;
// Assembly builtins argument slots size.
diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
index 7df5c41..fde0c58 100644
--- a/src/mips/disasm-mips.cc
+++ b/src/mips/disasm-mips.cc
@@ -112,7 +112,7 @@
void PrintUImm16(Instruction* instr);
void PrintSImm16(Instruction* instr);
void PrintXImm16(Instruction* instr);
- void PrintImm26(Instruction* instr);
+ void PrintXImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
// Printing of instruction name.
void PrintInstructionName(Instruction* instr);
@@ -273,9 +273,9 @@
// Print 26-bit immediate value.
-void Decoder::PrintImm26(Instruction* instr) {
- int32_t imm = instr->Imm26Value();
- out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
+void Decoder::PrintXImm26(Instruction* instr) {
+ uint32_t imm = instr->Imm26Value() << kImmFieldShift;
+ out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
@@ -383,9 +383,9 @@
}
return 6;
} else {
- ASSERT(STRING_STARTS_WITH(format, "imm26"));
- PrintImm26(instr);
- return 5;
+ ASSERT(STRING_STARTS_WITH(format, "imm26x"));
+ PrintXImm26(instr);
+ return 6;
}
}
case 'r': { // 'r: registers.
@@ -926,10 +926,10 @@
void Decoder::DecodeTypeJump(Instruction* instr) {
switch (instr->OpcodeFieldRaw()) {
case J:
- Format(instr, "j 'imm26");
+ Format(instr, "j 'imm26x");
break;
case JAL:
- Format(instr, "jal 'imm26");
+ Format(instr, "jal 'imm26x");
break;
default:
UNREACHABLE();
@@ -958,6 +958,7 @@
break;
}
default: {
+ Format(instr, "UNSUPPORTED");
UNSUPPORTED_MIPS();
}
}
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index 1899843..2c83893 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -30,7 +30,6 @@
#ifndef V8_MIPS_FRAMES_MIPS_H_
#define V8_MIPS_FRAMES_MIPS_H_
-
namespace v8 {
namespace internal {
@@ -40,13 +39,22 @@
static const int kNumRegs = 32;
static const RegList kJSCallerSaved =
- 1 << 2 | // v0
- 1 << 4 | // a0
- 1 << 5 | // a1
- 1 << 6 | // a2
- 1 << 7; // a3
+ 1 << 2 | // v0
+ 1 << 3 | // v1
+ 1 << 4 | // a0
+ 1 << 5 | // a1
+ 1 << 6 | // a2
+ 1 << 7 | // a3
+ 1 << 8 | // t0
+ 1 << 9 | // t1
+ 1 << 10 | // t2
+ 1 << 11 | // t3
+ 1 << 12 | // t4
+ 1 << 13 | // t5
+ 1 << 14 | // t6
+ 1 << 15; // t7
-static const int kNumJSCallerSaved = 5;
+static const int kNumJSCallerSaved = 14;
// Return the code of the n-th caller-saved register available to JavaScript
@@ -56,19 +64,30 @@
// Callee-saved registers preserved when switching from C to JavaScript.
static const RegList kCalleeSaved =
- // Saved temporaries.
- 1 << 16 | 1 << 17 | 1 << 18 | 1 << 19 |
- 1 << 20 | 1 << 21 | 1 << 22 | 1 << 23 |
- // fp.
- 1 << 30;
+ 1 << 16 | // s0
+ 1 << 17 | // s1
+ 1 << 18 | // s2
+ 1 << 19 | // s3
+ 1 << 20 | // s4
+ 1 << 21 | // s5
+ 1 << 22 | // s6 (roots in Javascript code)
+ 1 << 23 | // s7 (cp in Javascript code)
+ 1 << 30; // fp/s8
static const int kNumCalleeSaved = 9;
+static const RegList kCalleeSavedFPU =
+ 1 << 20 | // f20
+ 1 << 22 | // f22
+ 1 << 24 | // f24
+ 1 << 26 | // f26
+ 1 << 28 | // f28
+ 1 << 30; // f30
+static const int kNumCalleeSavedFPU = 6;
// Number of registers for which space is reserved in safepoints. Must be a
// multiple of 8.
-// TODO(mips): Only 8 registers may actually be sufficient. Revisit.
-static const int kNumSafepointRegisters = 16;
+static const int kNumSafepointRegisters = 24;
// Define the list of registers actually saved at safepoints.
// Note that the number of saved registers may be smaller than the reserved
@@ -82,37 +101,37 @@
static const int kUndefIndex = -1;
// Map with indexes on stack that corresponds to codes of saved registers.
static const int kSafepointRegisterStackIndexMap[kNumRegs] = {
- kUndefIndex,
- kUndefIndex,
- 0, // v0
- kUndefIndex,
- 1, // a0
- 2, // a1
- 3, // a2
- 4, // a3
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- 5, // Saved temporaries.
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- kUndefIndex,
- 13, // gp
- 14, // sp
- 15, // fp
+ kUndefIndex, // zero_reg
+ kUndefIndex, // at
+ 0, // v0
+ 1, // v1
+ 2, // a0
+ 3, // a1
+ 4, // a2
+ 5, // a3
+ 6, // t0
+ 7, // t1
+ 8, // t2
+ 9, // t3
+ 10, // t4
+ 11, // t5
+ 12, // t6
+ 13, // t7
+ 14, // s0
+ 15, // s1
+ 16, // s2
+ 17, // s3
+ 18, // s4
+ 19, // s5
+ 20, // s6
+ 21, // s7
+ kUndefIndex, // t8
+ kUndefIndex, // t9
+ kUndefIndex, // k0
+ kUndefIndex, // k1
+ kUndefIndex, // gp
+ kUndefIndex, // sp
+ 22, // fp
kUndefIndex
};
@@ -174,9 +193,6 @@
static const int kRArgsSlotsSize = 4 * kPointerSize;
static const int kRegularArgsSlotsSize = kRArgsSlotsSize;
- // C/C++ argument slots size.
- static const int kCArgSlotCount = 4;
- static const int kCArgsSlotsSize = kCArgSlotCount * kPointerSize;
// JS argument slots size.
static const int kJSArgsSlotsSize = 0 * kPointerSize;
// Assembly builtins argument slots size.
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index d3f8922..9a210c4 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -200,14 +200,14 @@
// Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ lw(a0, MemOperand(fp, parameter_offset));
// Store it in the context.
- __ li(a1, Operand(Context::SlotOffset(slot->index())));
+ __ li(a1, Operand(Context::SlotOffset(var->index())));
__ addu(a2, cp, a1);
__ sw(a0, MemOperand(a2, 0));
// Update the write barrier. This clobbers all involved
@@ -252,7 +252,7 @@
ArgumentsAccessStub stub(type);
__ CallStub(&stub);
- Move(arguments->AsSlot(), v0, a1, a2);
+ SetVar(arguments, v0, a1, a2);
}
if (FLAG_trace) {
@@ -266,17 +266,19 @@
scope()->VisitIllegalRedeclaration(this);
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
__ LoadRoot(t0, Heap::kStackLimitRootIndex);
__ Branch(&ok, hs, sp, Operand(t0));
@@ -370,24 +372,27 @@
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
__ push(result_register());
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
// For simplicity we always test the accumulator register.
- codegen()->Move(result_register(), slot);
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -620,29 +625,56 @@
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return MemOperand(fp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
}
- UNREACHABLE();
- return MemOperand(v0, 0);
+ return MemOperand(fp, offset);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
+ }
+}
+
+
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
// Use destination as scratch.
- MemOperand slot_operand = EmitSlotSearch(source, destination);
- __ lw(destination, slot_operand);
+ MemOperand location = VarOperand(var, dest);
+ __ lw(dest, location);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
+ __ sw(src, location);
+ // Emit the write barrier code if the location is in the heap.
+ if (var->IsContextSlot()) {
+ __ RecordWrite(scratch0,
+ Operand(Context::SlotOffset(var->index())),
+ scratch1,
+ src);
+ }
}
@@ -672,47 +704,33 @@
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
- __ sw(src, location);
- // Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- __ RecordWrite(scratch1,
- Operand(Context::SlotOffset(dst->index())),
- scratch2,
- src);
- }
-}
-
-
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- if (mode == Variable::CONST) {
- __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
- __ sw(t0, MemOperand(fp, SlotOffset(slot)));
- } else if (function != NULL) {
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
+ __ sw(result_register(), StackOperand(variable));
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ sw(t0, StackOperand(variable));
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -726,23 +744,28 @@
__ Check(ne, "Declaration in catch context.",
a1, Operand(t0));
}
- if (mode == Variable::CONST) {
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ sw(at, ContextOperand(cp, slot->index()));
- // No write barrier since the_hole_value is in old space.
- } else if (function != NULL) {
+ if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ sw(result_register(), ContextOperand(cp, slot->index()));
- int offset = Context::SlotOffset(slot->index());
+ __ sw(result_register(), ContextOperand(cp, variable->index()));
+ int offset = Context::SlotOffset(variable->index());
// We know that we have written a function, which is not a smi.
__ mov(a1, cp);
__ RecordWrite(a1, Operand(offset), a2, result_register());
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ sw(at, ContextOperand(cp, variable->index()));
+ // No write barrier since the_hole_value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ li(a2, Operand(variable->name()));
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -752,17 +775,16 @@
// Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value.
- if (mode == Variable::CONST) {
- __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
- __ Push(cp, a2, a1, a0);
- } else if (function != NULL) {
+ if (function != NULL) {
__ Push(cp, a2, a1);
// Push initial value for function declaration.
VisitForStackValue(function);
+ } else if (mode == Variable::CONST || mode == Variable::LET) {
+ __ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
+ __ Push(cp, a2, a1, a0);
} else {
ASSERT(Smi::FromInt(0) == 0);
- // No initial value!
- __ mov(a0, zero_reg); // Operand(Smi::FromInt(0)));
+ __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value.
__ Push(cp, a2, a1, a0);
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
@@ -772,19 +794,16 @@
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
// The context is the first argument.
- __ li(a2, Operand(pairs));
- __ li(a1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
- __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, a2, a1, a0);
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ li(a1, Operand(pairs));
+ __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
+ __ Push(cp, a1, a0);
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1088,10 +1107,9 @@
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register current = cp;
Register next = a1;
Register temp = a2;
@@ -1135,7 +1153,7 @@
}
__ lw(a0, GlobalObjectOperand());
- __ li(a2, Operand(slot->var()->name()));
+ __ li(a2, Operand(var->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT;
@@ -1144,15 +1162,14 @@
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = cp;
Register next = a3;
Register temp = t0;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1171,60 +1188,32 @@
// This function is used only for loads, not stores, so it's safe to
// return an cp-based operand (the write barrier cannot be allowed to
// destroy the cp register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ Branch(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ lw(v0, ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
- __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
- __ movz(v0, a0, at); // Conditional move.
- }
- __ Branch(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ lw(a1,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ li(a0, Operand(key_literal->handle()));
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ Branch(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ lw(v0, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
+ __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
+ __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole.
}
+ __ Branch(done);
}
}
@@ -1234,54 +1223,63 @@
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in a2 and the global
+ // object (receiver) in a0.
+ __ lw(a0, GlobalObjectOperand());
+ __ li(a2, Operand(var->name()));
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(v0);
+ break;
+ }
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in a2 and the global
- // object (receiver) in a0.
- __ lw(a0, GlobalObjectOperand());
- __ li(a2, Operand(var->name()));
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(v0);
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot()
+ ? "Context variable"
+ : "Stack variable");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ GetVar(v0, var);
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+ __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
+ if (var->mode() == Variable::LET) {
+ Label done;
+ __ Branch(&done, ne, at, Operand(zero_reg));
+ __ li(a0, Operand(var->name()));
+ __ push(a0);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&done);
+ } else {
+ __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
+ __ movz(v0, a0, at); // Conditional move: Undefined if TheHole.
+ }
+ context()->Plug(v0);
+ }
+ break;
+ }
- } else if (slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ li(a1, Operand(var->name()));
- __ Push(cp, a1); // Context and name.
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
-
- context()->Plug(v0);
-
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- MemOperand slot_operand = EmitSlotSearch(slot, a0);
- __ lw(v0, slot_operand);
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ subu(at, v0, at); // Sub as compare: at == 0 on eq.
- __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
- __ movz(v0, a0, at); // Conditional move.
- context()->Plug(v0);
- } else {
- context()->Plug(slot);
- }
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup variable");
+ __ li(a1, Operand(var->name()));
+ __ Push(cp, a1); // Context and name.
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
+ __ bind(&done);
+ context()->Plug(v0);
+ }
}
}
@@ -1819,14 +1817,8 @@
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in a0, variable name in
- // a2, and the global object in a1.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ mov(a0, result_register());
__ li(a2, Operand(var->name()));
__ lw(a1, GlobalObjectOperand());
@@ -1836,66 +1828,83 @@
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- // Detect const reinitialization by checking for the hole value.
- __ lw(a1, MemOperand(fp, SlotOffset(slot)));
- __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
- __ Branch(&skip, ne, a1, Operand(t0));
- __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(result_register());
- __ li(a0, Operand(slot->var()->name()));
- __ Push(cp, a0); // Context and name.
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ lw(a1, StackOperand(var));
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ Branch(&skip, ne, a1, Operand(t0));
+ __ sw(result_register(), StackOperand(var));
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(v0);
+ __ li(a0, Operand(var->name()));
+ __ Push(cp, a0); // Context and name.
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
- } else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
- break;
-
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, a1);
- // Perform the assignment and issue the write barrier.
- __ sw(result_register(), target);
+ } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(v0); // Value.
+ __ li(a1, Operand(var->name()));
+ __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, a1, a0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, a1);
+ __ lw(a3, location);
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ Branch(&assign, ne, a3, Operand(t0));
+ __ li(a3, Operand(var->name()));
+ __ push(a3);
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ // Perform the assignment.
+ __ bind(&assign);
+ __ sw(result_register(), location);
+ if (var->IsContextSlot()) {
// RecordWrite may destroy all its register arguments.
__ mov(a3, result_register());
- int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
+ int offset = Context::SlotOffset(var->index());
__ RecordWrite(a1, Operand(offset), a2, a3);
- break;
}
+ }
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(v0); // Value.
- __ li(a1, Operand(slot->var()->name()));
- __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
- __ Push(cp, a1, a0); // Context, name, strict mode.
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ } else if (var->mode() != Variable::CONST) {
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, a1);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ lw(a2, location);
+ __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
+ __ Check(eq, "Let binding re-initialization.", a2, Operand(t0));
+ }
+ // Perform the assignment.
+ __ sw(v0, location);
+ if (var->IsContextSlot()) {
+ __ mov(a3, v0);
+ __ RecordWrite(a1, Operand(Context::SlotOffset(var->index())), a2, a3);
+ }
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(v0); // Value.
+ __ li(a1, Operand(var->name()));
+ __ li(a0, Operand(Smi::FromInt(strict_mode_flag())));
+ __ Push(cp, a1, a0); // Context, name, strict mode.
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -2033,9 +2042,8 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2066,9 +2074,8 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
__ Call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2089,8 +2096,7 @@
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2113,8 +2119,13 @@
int receiver_offset = 2 + info_->scope()->num_parameters();
__ lw(a1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(a1);
- // Push the strict mode flag.
- __ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ li(a1, Operand(Smi::FromInt(strict_mode)));
__ push(a1);
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
@@ -2131,10 +2142,11 @@
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
@@ -2143,7 +2155,7 @@
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ push(a2); // Reserved receiver slot.
@@ -2151,16 +2163,16 @@
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
+
// If we know that eval can only be shadowed by eval-introduced
// variables we attempt to load the global eval function directly
// in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(v0);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2168,14 +2180,12 @@
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
+ // Push a copy of the function (found below the arguments) and
// resolve eval.
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(a1);
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in v0 (function) and
// v1 (receiver). Touch up the stack with the right values.
@@ -2184,37 +2194,32 @@
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, v0);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
// Push global object as receiver for the call IC.
__ lw(a0, GlobalObjectOperand());
__ push(a0);
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
__ bind(&slow);
// Call the runtime to find the function to call (returned in v0)
// and the object holding it (returned in v1).
__ push(context_register());
- __ li(a2, Operand(var->name()));
+ __ li(a2, Operand(proxy->name()));
__ push(a2);
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ Push(v0, v1); // Function, receiver.
@@ -2239,26 +2244,21 @@
// by LoadContextSlot. That object could be the hole if the
// receiver is implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
+ } else if (property != NULL) {
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
} else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ EmitKeyedCallWithIC(expr, property->key());
}
} else {
+ // Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ lw(a1, GlobalObjectOperand());
@@ -3206,7 +3206,7 @@
Label done, not_found;
- ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// a2 now holds finger offset as a smi.
__ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@@ -3570,9 +3570,7 @@
__ li(a2, Operand(expr->name()));
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arg_count,
- NOT_IN_LOOP,
- mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ Call(ic, mode, expr->id());
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -3588,32 +3586,32 @@
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ li(a1, Operand(Smi::FromInt(strict_mode_flag())));
__ push(a1);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(v0);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ lw(a2, GlobalObjectOperand());
__ li(a1, Operand(var->name()));
__ li(a0, Operand(Smi::FromInt(kNonStrictMode)));
__ Push(a2, a1, a0);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(v0);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
// Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects.
- context()->Plug(false);
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3888,8 +3886,10 @@
void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
+ ASSERT(!context()->IsEffect());
+ ASSERT(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ lw(a0, GlobalObjectOperand());
__ li(a2, Operand(proxy->name()));
@@ -3899,15 +3899,12 @@
__ Call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(v0);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ li(a0, Operand(proxy->name()));
@@ -4198,7 +4195,7 @@
// Cook return address in link register to stack (smi encoded Code* delta).
__ Subu(a1, ra, Operand(masm_->CodeObject()));
ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
- ASSERT_EQ(0, kSmiTag);
+ STATIC_ASSERT(0 == kSmiTag);
__ Addu(a1, a1, Operand(a1)); // Convert to smi.
__ push(a1);
}
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 85cb916..a76c215 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -146,7 +146,7 @@
__ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at,
scratch1,
- Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
+ Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
__ Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
@@ -196,9 +196,9 @@
const int kElementsStartOffset = StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
__ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
__ Branch(miss, ne, at, Operand(zero_reg));
@@ -338,7 +338,7 @@
__ Addu(scratch1, elements,
Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// The key is a smi.
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
__ addu(at, at, scratch1);
__ lw(scratch2, MemOperand(at));
@@ -372,7 +372,7 @@
// Is the string a symbol?
// map: key map
__ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
- ASSERT(kSymbolTag != 0);
+ STATIC_ASSERT(kSymbolTag != 0);
__ And(at, hash, Operand(kIsSymbolMask));
__ Branch(not_symbol, eq, at, Operand(zero_reg));
}
@@ -395,7 +395,6 @@
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -732,9 +731,7 @@
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, a0, a2, a3, t0, t1);
@@ -1269,7 +1266,7 @@
__ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
__ Branch(&slow, hs, key, Operand(t0));
// Calculate key + 1 as smi.
- ASSERT_EQ(0, kSmiTag);
+ STATIC_ASSERT(0 == kSmiTag);
__ Addu(t3, key, Operand(Smi::FromInt(1)));
__ sw(t3, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ Branch(&fast);
@@ -1395,10 +1392,8 @@
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, a1, a2, a3, t0, t1);
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index c7f727b..4c48ef1 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -441,7 +441,7 @@
const int kDetailsOffset =
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
lw(reg1, FieldMemOperand(reg2, kDetailsOffset));
- And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
+ And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
@@ -703,52 +703,114 @@
void MacroAssembler::MultiPush(RegList regs) {
- int16_t NumSaved = 0;
- int16_t NumToPush = NumberOfBitsSet(regs);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kPointerSize;
- addiu(sp, sp, -4 * NumToPush);
+ Subu(sp, sp, Operand(stack_offset));
for (int16_t i = kNumRegisters; i > 0; i--) {
if ((regs & (1 << i)) != 0) {
- sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
+ stack_offset -= kPointerSize;
+ sw(ToRegister(i), MemOperand(sp, stack_offset));
}
}
}
void MacroAssembler::MultiPushReversed(RegList regs) {
- int16_t NumSaved = 0;
- int16_t NumToPush = NumberOfBitsSet(regs);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kPointerSize;
- addiu(sp, sp, -4 * NumToPush);
+ Subu(sp, sp, Operand(stack_offset));
for (int16_t i = 0; i < kNumRegisters; i++) {
if ((regs & (1 << i)) != 0) {
- sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
+ stack_offset -= kPointerSize;
+ sw(ToRegister(i), MemOperand(sp, stack_offset));
}
}
}
void MacroAssembler::MultiPop(RegList regs) {
- int16_t NumSaved = 0;
+ int16_t stack_offset = 0;
for (int16_t i = 0; i < kNumRegisters; i++) {
if ((regs & (1 << i)) != 0) {
- lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
+ lw(ToRegister(i), MemOperand(sp, stack_offset));
+ stack_offset += kPointerSize;
}
}
- addiu(sp, sp, 4 * NumSaved);
+ addiu(sp, sp, stack_offset);
}
void MacroAssembler::MultiPopReversed(RegList regs) {
- int16_t NumSaved = 0;
+ int16_t stack_offset = 0;
for (int16_t i = kNumRegisters; i > 0; i--) {
if ((regs & (1 << i)) != 0) {
- lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
+ lw(ToRegister(i), MemOperand(sp, stack_offset));
+ stack_offset += kPointerSize;
}
}
- addiu(sp, sp, 4 * NumSaved);
+ addiu(sp, sp, stack_offset);
+}
+
+
+void MacroAssembler::MultiPushFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kDoubleSize;
+
+ Subu(sp, sp, Operand(stack_offset));
+ for (int16_t i = kNumRegisters; i > 0; i--) {
+ if ((regs & (1 << i)) != 0) {
+ stack_offset -= kDoubleSize;
+ sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ }
+ }
+}
+
+
+void MacroAssembler::MultiPushReversedFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t num_to_push = NumberOfBitsSet(regs);
+ int16_t stack_offset = num_to_push * kDoubleSize;
+
+ Subu(sp, sp, Operand(stack_offset));
+ for (int16_t i = 0; i < kNumRegisters; i++) {
+ if ((regs & (1 << i)) != 0) {
+ stack_offset -= kDoubleSize;
+ sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ }
+ }
+}
+
+
+void MacroAssembler::MultiPopFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t stack_offset = 0;
+
+ for (int16_t i = 0; i < kNumRegisters; i++) {
+ if ((regs & (1 << i)) != 0) {
+ ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ stack_offset += kDoubleSize;
+ }
+ }
+ addiu(sp, sp, stack_offset);
+}
+
+
+void MacroAssembler::MultiPopReversedFPU(RegList regs) {
+ CpuFeatures::Scope scope(FPU);
+ int16_t stack_offset = 0;
+
+ for (int16_t i = kNumRegisters; i > 0; i--) {
+ if ((regs & (1 << i)) != 0) {
+ ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
+ stack_offset += kDoubleSize;
+ }
+ }
+ addiu(sp, sp, stack_offset);
}
@@ -2275,7 +2337,7 @@
li(t0, Operand(StackHandler::TRY_FINALLY));
}
// Save the current handler as the next handler.
- li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(t1, MemOperand(t2));
addiu(sp, sp, -StackHandlerConstants::kSize);
@@ -2297,7 +2359,7 @@
li(t0, Operand(StackHandler::ENTRY));
// Save the current handler as the next handler.
- li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(t1, MemOperand(t2));
ASSERT(Smi::FromInt(0) == 0); // Used for no context.
@@ -2319,7 +2381,7 @@
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
pop(a1);
Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
- li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
sw(a1, MemOperand(at));
}
@@ -2337,7 +2399,7 @@
STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize);
// Drop the sp to the top of the handler.
- li(a3, Operand(ExternalReference(Isolate::k_handler_address,
+ li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
isolate())));
lw(sp, MemOperand(a3));
@@ -2400,7 +2462,7 @@
Move(v0, value);
// Drop sp to the top stack handler.
- li(a3, Operand(ExternalReference(Isolate::k_handler_address, isolate())));
+ li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(sp, MemOperand(a3));
// Unwind the handlers until the ENTRY handler is found.
@@ -2423,7 +2485,7 @@
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address, isolate());
+ Isolate::kExternalCaughtExceptionAddress, isolate());
li(a0, Operand(false, RelocInfo::NONE));
li(a2, Operand(external_caught));
sw(a0, MemOperand(a2));
@@ -2431,7 +2493,7 @@
// Set pending exception and v0 to out of memory exception.
Failure* out_of_memory = Failure::OutOfMemoryException();
li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address,
+ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate())));
sw(v0, MemOperand(a2));
}
@@ -2753,6 +2815,46 @@
}
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
+void MacroAssembler::AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ InitializeNewString(result,
+ length,
+ Heap::kSlicedAsciiStringMapRootIndex,
+ scratch1,
+ scratch2);
+}
+
+
// Allocates a heap number or jumps to the label if the young space is full and
// a scavenge is needed.
void MacroAssembler::AllocateHeapNumber(Register result,
@@ -2873,7 +2975,7 @@
void MacroAssembler::CheckFastElements(Register map,
Register scratch,
Label* fail) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
Branch(fail, hi, scratch, Operand(Map::kMaximumBitField2FastElementValue));
}
@@ -3871,9 +3973,9 @@
sw(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
- li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
sw(fp, MemOperand(t8));
- li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
sw(cp, MemOperand(t8));
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
@@ -3923,11 +4025,11 @@
}
// Clear top frame.
- li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
sw(zero_reg, MemOperand(t8));
// Restore current context from top and clear it in debug mode.
- li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate())));
+ li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
lw(cp, MemOperand(t8));
#ifdef DEBUG
sw(a3, MemOperand(t8));
@@ -4151,11 +4253,9 @@
// mips, even though those argument slots are not normally used.
// Remaining arguments are pushed on the stack, above (higher address than)
// the argument slots.
- ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
0 : num_arguments - kRegisterPassedArguments) +
- (StandardFrameConstants::kCArgsSlotsSize /
- kPointerSize);
+ kCArgSlotCount;
if (frame_alignment > kPointerSize) {
// Make stack end at alignment and make room for num_arguments - 4 words
// and the original value of sp.
@@ -4227,11 +4327,9 @@
Call(function);
- ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
0 : num_arguments - kRegisterPassedArguments) +
- (StandardFrameConstants::kCArgsSlotsSize /
- kPointerSize);
+ kCArgSlotCount;
if (OS::ActivationFrameAlignment() > kPointerSize) {
lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 0fcf6f1..5dd012e 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -362,6 +362,16 @@
Register scratch1,
Register scratch2,
Label* gc_required);
+ void AllocateTwoByteSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void AllocateAsciiSlicedString(Register result,
+ Register length,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
// Allocates a heap number or jumps to the gc_required label if the young
// space is full and a scavenge is needed. All registers are clobbered also
@@ -442,6 +452,9 @@
void MultiPush(RegList regs);
void MultiPushReversed(RegList regs);
+ void MultiPushFPU(RegList regs);
+ void MultiPushReversedFPU(RegList regs);
+
// Lower case push() for compatibility with arch-independent code.
void push(Register src) {
Addu(sp, sp, Operand(-kPointerSize));
@@ -487,6 +500,9 @@
void MultiPop(RegList regs);
void MultiPopReversed(RegList regs);
+ void MultiPopFPU(RegList regs);
+ void MultiPopReversedFPU(RegList regs);
+
// Lower case pop() for compatibility with arch-independent code.
void pop(Register dst) {
lw(dst, MemOperand(sp, 0));
@@ -1197,10 +1213,9 @@
// Generate a MemOperand for storing arguments 5..N on the stack
// when calling CallCFunction().
static inline MemOperand CFunctionArgumentOperand(int index) {
- ASSERT(index > StandardFrameConstants::kCArgSlotCount);
+ ASSERT(index > kCArgSlotCount);
// Argument 5 takes the slot just past the four Arg-slots.
- int offset =
- (index - 5) * kPointerSize + StandardFrameConstants::kCArgsSlotsSize;
+ int offset = (index - 5) * kPointerSize + kCArgsSlotsSize;
return MemOperand(sp, offset);
}
diff --git a/src/mips/regexp-macro-assembler-mips.h b/src/mips/regexp-macro-assembler-mips.h
index 7fe0c88..d42d4cf 100644
--- a/src/mips/regexp-macro-assembler-mips.h
+++ b/src/mips/regexp-macro-assembler-mips.h
@@ -118,6 +118,7 @@
static int CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame);
+
private:
// Offsets from frame_pointer() of function parameters and stored registers.
static const int kFramePointer = 0;
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index 3b38695..17c1897 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -33,6 +33,7 @@
#if defined(V8_TARGET_ARCH_MIPS)
+#include "cpu.h"
#include "disasm.h"
#include "assembler.h"
#include "globals.h" // Need the BitCast.
@@ -1215,6 +1216,8 @@
int Simulator::ReadW(int32_t addr, Instruction* instr) {
if (addr >=0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger.
+ PrintF("Memory read from bad address: 0x%08x, pc=0x%08x\n",
+ addr, reinterpret_cast<intptr_t>(instr));
MipsDebugger dbg(this);
dbg.Debug();
}
@@ -1234,6 +1237,8 @@
void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
if (addr >= 0 && addr < 0x400) {
// This has to be a NULL-dereference, drop into debugger.
+ PrintF("Memory write to bad address: 0x%08x, pc=0x%08x\n",
+ addr, reinterpret_cast<intptr_t>(instr));
MipsDebugger dbg(this);
dbg.Debug();
}
@@ -2716,7 +2721,7 @@
// Store remaining arguments on stack, from low to high memory.
intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
for (int i = 4; i < argument_count; i++) {
- stack_argument[i - 4 + kArgsSlotsNum] = va_arg(parameters, int32_t);
+ stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
}
va_end(parameters);
set_register(sp, entry_stack);
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index c17a658..5b94973 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -3099,7 +3099,7 @@
// -- a1 : receiver
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(a1,
@@ -3191,7 +3191,7 @@
// -- a3 : scratch
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
@@ -3442,25 +3442,25 @@
}
-static bool IsElementTypeSigned(JSObject::ElementsKind elements_kind) {
+static bool IsElementTypeSigned(ElementsKind elements_kind) {
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
return true;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
return false;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
return false;
}
@@ -3470,7 +3470,7 @@
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- ra : return address
// -- a0 : key
@@ -3501,36 +3501,36 @@
// We are not untagging smi key and instead work with it
// as if it was premultiplied by 2.
- ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
+ STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
Register value = a2;
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ srl(t2, key, 1);
__ addu(t3, a3, t2);
__ lb(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ srl(t2, key, 1);
__ addu(t3, a3, t2);
__ lbu(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ addu(t3, a3, key);
__ lh(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ addu(t3, a3, key);
__ lhu(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t2, key, 1);
__ addu(t3, a3, t2);
__ lw(value, MemOperand(t3, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
__ sll(t3, t2, 2);
__ addu(t3, a3, t3);
if (CpuFeatures::IsSupported(FPU)) {
@@ -3540,7 +3540,7 @@
__ lw(value, MemOperand(t3, 0));
}
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ sll(t2, key, 2);
__ addu(t3, a3, t2);
if (CpuFeatures::IsSupported(FPU)) {
@@ -3552,10 +3552,10 @@
__ lw(a3, MemOperand(t3, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3569,7 +3569,7 @@
// f0: value (if FPU is supported)
// a2/a3: value (if FPU is not supported)
- if (elements_kind == JSObject::EXTERNAL_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_INT_ELEMENTS) {
// For the Int and UnsignedInt array types, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
@@ -3611,7 +3611,7 @@
__ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// The test is different for unsigned int values. Since we need
// the value to be in the range of a positive smi, we can't
// handle either of the top two bits being set in the value.
@@ -3682,7 +3682,7 @@
__ mov(v0, t2);
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
if (CpuFeatures::IsSupported(FPU)) {
@@ -3749,7 +3749,7 @@
__ Ret();
}
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatures::Scope scope(FPU);
// Allocate a HeapNumber for the result. Don't use a0 and a1 as
@@ -3803,7 +3803,7 @@
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ---------- S t a t e --------------
// -- a0 : value
// -- a1 : key
@@ -3838,7 +3838,7 @@
// a3: external array.
// t0: key (integer).
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// Double to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(value, &slow);
} else {
@@ -3852,7 +3852,7 @@
// t1: value (integer).
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
// Clamp the value to [0..255].
// v0 is used as a scratch register here.
Label done;
@@ -3869,28 +3869,28 @@
__ sb(t1, MemOperand(t8, 0));
}
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ addu(t8, a3, t0);
__ sb(t1, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ sll(t8, t0, 1);
__ addu(t8, a3, t8);
__ sh(t1, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ sw(t1, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
// Perform int-to-float conversion and store to memory.
StoreIntAsFloat(masm, a3, t0, t1, t2, t3, t4);
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ sll(t8, t0, 3);
__ addu(a3, a3, t8);
// a3: effective address of the double element
@@ -3912,10 +3912,10 @@
__ sw(t3, MemOperand(a3, Register::kSizeInBytes));
}
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3924,7 +3924,7 @@
__ mov(v0, value);
__ Ret();
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
// a3: external array.
// t0: index (integer).
__ bind(&check_heap_number);
@@ -3945,12 +3945,12 @@
__ ldc1(f0, FieldMemOperand(a0, HeapNumber::kValueOffset));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvt_s_d(f0, f0);
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ swc1(f0, MemOperand(t8, 0));
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sll(t8, t0, 3);
__ addu(t8, a3, t8);
__ sdc1(f0, MemOperand(t8, 0));
@@ -3958,30 +3958,30 @@
__ EmitECMATruncate(t3, f0, f2, t2, t1, t5);
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ addu(t8, a3, t0);
__ sb(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ sll(t8, t0, 1);
__ addu(t8, a3, t8);
__ sh(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ sw(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3997,7 +3997,7 @@
__ lw(t3, FieldMemOperand(value, HeapNumber::kExponentOffset));
__ lw(t4, FieldMemOperand(value, HeapNumber::kMantissaOffset));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
Label done, nan_or_infinity_or_zero;
static const int kMantissaInHiWordShift =
kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
@@ -4062,7 +4062,7 @@
__ srl(t4, t4, kMantissaInLoWordShift);
__ or_(t3, t6, t4);
__ Branch(&done);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ sll(t8, t0, 3);
__ addu(t8, a3, t8);
// t8: effective address of destination element.
@@ -4128,30 +4128,30 @@
// Result is in t3.
// This switch block should be exactly the same as above (FPU mode).
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ addu(t8, a3, t0);
__ sb(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ sll(t8, t0, 1);
__ addu(t8, a3, t8);
__ sh(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ sll(t8, t0, 2);
__ addu(t8, a3, t8);
__ sw(t3, MemOperand(t8, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -4213,7 +4213,7 @@
// Load the result and make sure it's not the hole.
__ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t0, t0, a3);
__ lw(t0, MemOperand(t0));
@@ -4344,7 +4344,7 @@
__ Addu(scratch,
elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
__ Addu(scratch3, scratch2, scratch);
__ sw(value_reg, MemOperand(scratch3));
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 4f5fe96..a791dbb 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -29,8 +29,6 @@
#include <bzlib.h>
#endif
#include <signal.h>
-#include <string>
-#include <map>
#include "v8.h"
@@ -86,16 +84,6 @@
};
-// We statically allocate a set of local counters to be used if we
-// don't want to store the stats in a memory-mapped file
-static CounterCollection local_counters;
-
-
-typedef std::map<std::string, int*> CounterMap;
-typedef std::map<std::string, int*>::iterator CounterMapIterator;
-static CounterMap counter_table_;
-
-
class Compressor {
public:
virtual ~Compressor() {}
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 4da360b..8de7162 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -164,6 +164,9 @@
case JS_PROXY_TYPE:
JSProxy::cast(this)->JSProxyVerify();
break;
+ case JS_FUNCTION_PROXY_TYPE:
+ JSFunctionProxy::cast(this)->JSFunctionProxyVerify();
+ break;
case FOREIGN_TYPE:
Foreign::cast(this)->ForeignVerify();
break;
@@ -257,9 +260,9 @@
(map()->inobject_properties() + properties()->length() -
map()->NextFreePropertyIndex()));
}
- ASSERT(map()->has_fast_elements() ==
- (elements()->map() == GetHeap()->fixed_array_map() ||
- elements()->map() == GetHeap()->fixed_cow_array_map()));
+ ASSERT_EQ(map()->has_fast_elements(),
+ (elements()->map() == GetHeap()->fixed_array_map() ||
+ elements()->map() == GetHeap()->fixed_cow_array_map()));
ASSERT(map()->has_fast_elements() == HasFastElements());
}
@@ -536,6 +539,15 @@
VerifyPointer(handler());
}
+
+void JSFunctionProxy::JSFunctionProxyVerify() {
+ ASSERT(IsJSFunctionProxy());
+ JSProxyVerify();
+ VerifyPointer(call_trap());
+ VerifyPointer(construct_trap());
+}
+
+
void Foreign::ForeignVerify() {
ASSERT(IsForeign());
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index ff3be03..8796865 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2004,7 +2004,7 @@
bool DescriptorArray::IsTransition(int descriptor_number) {
PropertyType t = GetType(descriptor_number);
return t == MAP_TRANSITION || t == CONSTANT_TRANSITION ||
- t == EXTERNAL_ARRAY_TRANSITION;
+ t == ELEMENTS_TRANSITION;
}
@@ -2871,7 +2871,7 @@
void Code::set_flags(Code::Flags flags) {
- STATIC_ASSERT(Code::NUMBER_OF_KINDS <= (kFlagsKindMask >> kFlagsKindShift)+1);
+ STATIC_ASSERT(Code::NUMBER_OF_KINDS <= KindField::kMax + 1);
// Make sure that all call stubs have an arguments count.
ASSERT((ExtractKindFromFlags(flags) != CALL_IC &&
ExtractKindFromFlags(flags) != KEYED_CALL_IC) ||
@@ -2885,11 +2885,6 @@
}
-InLoopFlag Code::ic_in_loop() {
- return ExtractICInLoopFromFlags(flags());
-}
-
-
InlineCacheState Code::ic_state() {
InlineCacheState result = ExtractICStateFromFlags(flags());
// Only allow uninitialized or debugger states for non-IC code
@@ -2955,13 +2950,31 @@
bool Code::has_deoptimization_support() {
ASSERT(kind() == FUNCTION);
- return READ_BYTE_FIELD(this, kHasDeoptimizationSupportOffset) == 1;
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ return FullCodeFlagsHasDeoptimizationSupportField::decode(flags);
}
void Code::set_has_deoptimization_support(bool value) {
ASSERT(kind() == FUNCTION);
- WRITE_BYTE_FIELD(this, kHasDeoptimizationSupportOffset, value ? 1 : 0);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ flags = FullCodeFlagsHasDeoptimizationSupportField::update(flags, value);
+ WRITE_BYTE_FIELD(this, kFullCodeFlags, flags);
+}
+
+
+bool Code::has_debug_break_slots() {
+ ASSERT(kind() == FUNCTION);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ return FullCodeFlagsHasDebugBreakSlotsField::decode(flags);
+}
+
+
+void Code::set_has_debug_break_slots(bool value) {
+ ASSERT(kind() == FUNCTION);
+ byte flags = READ_BYTE_FIELD(this, kFullCodeFlags);
+ flags = FullCodeFlagsHasDebugBreakSlotsField::update(flags, value);
+ WRITE_BYTE_FIELD(this, kFullCodeFlags, flags);
}
@@ -3095,7 +3108,6 @@
Code::Flags Code::ComputeFlags(Kind kind,
- InLoopFlag in_loop,
InlineCacheState ic_state,
ExtraICState extra_ic_state,
PropertyType type,
@@ -3104,26 +3116,17 @@
// Extra IC state is only allowed for call IC stubs or for store IC
// stubs.
ASSERT(extra_ic_state == kNoExtraICState ||
- (kind == CALL_IC) ||
- (kind == STORE_IC) ||
- (kind == KEYED_STORE_IC));
+ kind == CALL_IC ||
+ kind == STORE_IC ||
+ kind == KEYED_STORE_IC);
// Compute the bit mask.
- int bits = kind << kFlagsKindShift;
- if (in_loop) bits |= kFlagsICInLoopMask;
- bits |= ic_state << kFlagsICStateShift;
- bits |= type << kFlagsTypeShift;
- bits |= extra_ic_state << kFlagsExtraICStateShift;
- bits |= argc << kFlagsArgumentsCountShift;
- if (holder == PROTOTYPE_MAP) bits |= kFlagsCacheInPrototypeMapMask;
- // Cast to flags and validate result before returning it.
- Flags result = static_cast<Flags>(bits);
- ASSERT(ExtractKindFromFlags(result) == kind);
- ASSERT(ExtractICStateFromFlags(result) == ic_state);
- ASSERT(ExtractICInLoopFromFlags(result) == in_loop);
- ASSERT(ExtractTypeFromFlags(result) == type);
- ASSERT(ExtractExtraICStateFromFlags(result) == extra_ic_state);
- ASSERT(ExtractArgumentsCountFromFlags(result) == argc);
- return result;
+ int bits = KindField::encode(kind)
+ | ICStateField::encode(ic_state)
+ | TypeField::encode(type)
+ | ExtraICStateField::encode(extra_ic_state)
+ | (argc << kArgumentsCountShift)
+ | CacheHolderField::encode(holder);
+ return static_cast<Flags>(bits);
}
@@ -3131,56 +3134,43 @@
PropertyType type,
ExtraICState extra_ic_state,
InlineCacheHolderFlag holder,
- InLoopFlag in_loop,
int argc) {
- return ComputeFlags(
- kind, in_loop, MONOMORPHIC, extra_ic_state, type, argc, holder);
+ return ComputeFlags(kind, MONOMORPHIC, extra_ic_state, type, argc, holder);
}
Code::Kind Code::ExtractKindFromFlags(Flags flags) {
- int bits = (flags & kFlagsKindMask) >> kFlagsKindShift;
- return static_cast<Kind>(bits);
+ return KindField::decode(flags);
}
InlineCacheState Code::ExtractICStateFromFlags(Flags flags) {
- int bits = (flags & kFlagsICStateMask) >> kFlagsICStateShift;
- return static_cast<InlineCacheState>(bits);
+ return ICStateField::decode(flags);
}
Code::ExtraICState Code::ExtractExtraICStateFromFlags(Flags flags) {
- int bits = (flags & kFlagsExtraICStateMask) >> kFlagsExtraICStateShift;
- return static_cast<ExtraICState>(bits);
-}
-
-
-InLoopFlag Code::ExtractICInLoopFromFlags(Flags flags) {
- int bits = (flags & kFlagsICInLoopMask);
- return bits != 0 ? IN_LOOP : NOT_IN_LOOP;
+ return ExtraICStateField::decode(flags);
}
PropertyType Code::ExtractTypeFromFlags(Flags flags) {
- int bits = (flags & kFlagsTypeMask) >> kFlagsTypeShift;
- return static_cast<PropertyType>(bits);
+ return TypeField::decode(flags);
}
int Code::ExtractArgumentsCountFromFlags(Flags flags) {
- return (flags & kFlagsArgumentsCountMask) >> kFlagsArgumentsCountShift;
+ return (flags & kArgumentsCountMask) >> kArgumentsCountShift;
}
InlineCacheHolderFlag Code::ExtractCacheHolderFromFlags(Flags flags) {
- int bits = (flags & kFlagsCacheInPrototypeMapMask);
- return bits != 0 ? PROTOTYPE_MAP : OWN_MAP;
+ return CacheHolderField::decode(flags);
}
Code::Flags Code::RemoveTypeFromFlags(Flags flags) {
- int bits = flags & ~kFlagsTypeMask;
+ int bits = flags & ~TypeField::kMask;
return static_cast<Flags>(bits);
}
@@ -3263,7 +3253,7 @@
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(JSObject::FAST_ELEMENTS);
+ new_map->set_elements_kind(FAST_ELEMENTS);
isolate()->counters()->map_to_fast_elements()->Increment();
return new_map;
}
@@ -3276,7 +3266,7 @@
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(JSObject::FAST_DOUBLE_ELEMENTS);
+ new_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
isolate()->counters()->map_to_fast_double_elements()->Increment();
return new_map;
}
@@ -3289,7 +3279,7 @@
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(JSObject::DICTIONARY_ELEMENTS);
+ new_map->set_elements_kind(DICTIONARY_ELEMENTS);
isolate()->counters()->map_to_slow_elements()->Increment();
return new_map;
}
@@ -3920,7 +3910,16 @@
ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
-ACCESSORS(JSProxy, padding, Object, kPaddingOffset)
+ACCESSORS(JSFunctionProxy, call_trap, Object, kCallTrapOffset)
+ACCESSORS(JSFunctionProxy, construct_trap, Object, kConstructTrapOffset)
+
+
+void JSProxy::InitializeBody(int object_size, Object* value) {
+ ASSERT(!value->IsHeapObject() || !GetHeap()->InNewSpace(value));
+ for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
+ WRITE_FIELD(this, offset, value);
+ }
+}
ACCESSORS(JSWeakMap, table, ObjectHashTable, kTableOffset)
@@ -4102,7 +4101,7 @@
}
-JSObject::ElementsKind JSObject::GetElementsKind() {
+ElementsKind JSObject::GetElementsKind() {
ElementsKind kind = map()->elements_kind();
ASSERT((kind == FAST_ELEMENTS &&
(elements()->map() == GetHeap()->fixed_array_map() ||
@@ -4441,9 +4440,7 @@
void AccessorInfo::set_property_attributes(PropertyAttributes attributes) {
- ASSERT(AttributesField::is_valid(attributes));
- int rest_value = flag()->value() & ~AttributesField::mask();
- set_flag(Smi::FromInt(rest_value | AttributesField::encode(attributes)));
+ set_flag(Smi::FromInt(AttributesField::update(flag()->value(), attributes)));
}
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 3573572..0398572 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -151,6 +151,9 @@
case JS_PROXY_TYPE:
JSProxy::cast(this)->JSProxyPrint(out);
break;
+ case JS_FUNCTION_PROXY_TYPE:
+ JSFunctionProxy::cast(this)->JSFunctionProxyPrint(out);
+ break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapPrint(out);
break;
@@ -588,6 +591,19 @@
}
+void JSFunctionProxy::JSFunctionProxyPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSFunctionProxy");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - handler = ");
+ handler()->Print(out);
+ PrintF(out, " - call_trap = ");
+ call_trap()->Print(out);
+ PrintF(out, " - construct_trap = ");
+ construct_trap()->Print(out);
+ PrintF(out, "\n");
+}
+
+
void JSWeakMap::JSWeakMapPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSWeakMap");
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index bde9e83..0aa21dd 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -105,6 +105,11 @@
kVisitStructGeneric,
JSProxy::kSize);
+ case JS_FUNCTION_PROXY_TYPE:
+ return GetVisitorIdForSize(kVisitStruct,
+ kVisitStructGeneric,
+ JSFunctionProxy::kSize);
+
case FOREIGN_TYPE:
return GetVisitorIdForSize(kVisitDataObject,
kVisitDataObjectGeneric,
diff --git a/src/objects.cc b/src/objects.cc
index 0660dba..6085b4e 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -41,7 +41,6 @@
#include "objects-visiting.h"
#include "macro-assembler.h"
#include "safepoint-table.h"
-#include "scanner-base.h"
#include "string-stream.h"
#include "utils.h"
#include "vm-state-inl.h"
@@ -85,7 +84,7 @@
MaybeObject* Object::ToObject() {
- if (IsJSObject()) {
+ if (IsJSReceiver()) {
return this;
} else if (IsNumber()) {
Isolate* isolate = Isolate::Current();
@@ -238,6 +237,7 @@
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
// Get the derived `get' property.
trap = isolate->derived_get_trap();
@@ -592,7 +592,7 @@
return holder->GetPropertyWithInterceptor(recvr, name, attributes);
}
case MAP_TRANSITION:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
break;
@@ -628,6 +628,7 @@
} else if (heap_object->IsBoolean()) {
holder = global_context->boolean_function()->instance_prototype();
} else if (heap_object->IsJSProxy()) {
+ // TODO(rossberg): do something
return heap->undefined_value(); // For now...
} else {
// Undefined and null have no indexed properties.
@@ -1048,6 +1049,7 @@
global_object ? "Global Object: " : "",
vowel ? "n" : "");
accumulator->Put(str);
+ accumulator->Put('>');
printed = true;
}
}
@@ -1173,6 +1175,12 @@
HeapNumber::cast(this)->HeapNumberPrint(accumulator);
accumulator->Put('>');
break;
+ case JS_PROXY_TYPE:
+ accumulator->Add("<JSProxy>");
+ break;
+ case JS_FUNCTION_PROXY_TYPE:
+ accumulator->Add("<JSFunctionProxy>");
+ break;
case FOREIGN_TYPE:
accumulator->Add("<Foreign>");
break;
@@ -1251,6 +1259,9 @@
case JS_PROXY_TYPE:
JSProxy::BodyDescriptor::IterateBody(this, v);
break;
+ case JS_FUNCTION_PROXY_TYPE:
+ JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
+ break;
case FOREIGN_TYPE:
reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
break;
@@ -1435,13 +1446,12 @@
// it's unrelated to properties.
int descriptor_index = old_descriptors->Search(name);
- // External array transitions are stored in the descriptor for property "",
- // which is not a identifier and should have forced a switch to slow
- // properties above.
+ // Element transitions are stored in the descriptor for property "", which is
+ // not a identifier and should have forced a switch to slow properties above.
ASSERT(descriptor_index == DescriptorArray::kNotFound ||
- old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
+ old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
- old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
+ old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
bool allow_map_transition =
can_insert_transition &&
(isolate->context()->global_context()->object_function()->map() != map());
@@ -1989,61 +1999,25 @@
}
-static JSObject::ElementsKind GetElementsKindFromExternalArrayType(
- ExternalArrayType array_type) {
- switch (array_type) {
- case kExternalByteArray:
- return JSObject::EXTERNAL_BYTE_ELEMENTS;
- break;
- case kExternalUnsignedByteArray:
- return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
- break;
- case kExternalShortArray:
- return JSObject::EXTERNAL_SHORT_ELEMENTS;
- break;
- case kExternalUnsignedShortArray:
- return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
- break;
- case kExternalIntArray:
- return JSObject::EXTERNAL_INT_ELEMENTS;
- break;
- case kExternalUnsignedIntArray:
- return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS;
- break;
- case kExternalFloatArray:
- return JSObject::EXTERNAL_FLOAT_ELEMENTS;
- break;
- case kExternalDoubleArray:
- return JSObject::EXTERNAL_DOUBLE_ELEMENTS;
- break;
- case kExternalPixelArray:
- return JSObject::EXTERNAL_PIXEL_ELEMENTS;
- break;
- }
- UNREACHABLE();
- return JSObject::DICTIONARY_ELEMENTS;
-}
-
-
-MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
- bool safe_to_add_transition) {
+MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind,
+ bool safe_to_add_transition) {
Heap* current_heap = heap();
DescriptorArray* descriptors = instance_descriptors();
- String* external_array_sentinel_name = current_heap->empty_symbol();
+ String* elements_transition_sentinel_name = current_heap->empty_symbol();
if (safe_to_add_transition) {
// It's only safe to manipulate the descriptor array if it would be
// safe to add a transition.
ASSERT(!is_shared()); // no transitions can be added to shared maps.
- // Check if the external array transition already exists.
+ // Check if the elements transition already exists.
DescriptorLookupCache* cache =
current_heap->isolate()->descriptor_lookup_cache();
- int index = cache->Lookup(descriptors, external_array_sentinel_name);
+ int index = cache->Lookup(descriptors, elements_transition_sentinel_name);
if (index == DescriptorLookupCache::kAbsent) {
- index = descriptors->Search(external_array_sentinel_name);
+ index = descriptors->Search(elements_transition_sentinel_name);
cache->Update(descriptors,
- external_array_sentinel_name,
+ elements_transition_sentinel_name,
index);
}
@@ -2051,8 +2025,8 @@
// return it.
if (index != DescriptorArray::kNotFound) {
PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
- if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
- details.array_type() == array_type) {
+ if (details.type() == ELEMENTS_TRANSITION &&
+ details.elements_kind() == elements_kind) {
return descriptors->GetValue(index);
} else {
safe_to_add_transition = false;
@@ -2060,28 +2034,29 @@
}
}
- // No transition to an existing external array map. Make a new one.
+ // No transition to an existing map for the given ElementsKind. Make a new
+ // one.
Object* obj;
{ MaybeObject* maybe_map = CopyDropTransitions();
if (!maybe_map->ToObject(&obj)) return maybe_map;
}
Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type));
+ new_map->set_elements_kind(elements_kind);
GetIsolate()->counters()->map_to_external_array_elements()->Increment();
// Only remember the map transition if the object's map is NOT equal to the
// global object_function's map and there is not an already existing
- // non-matching external array transition.
+ // non-matching element transition.
bool allow_map_transition =
safe_to_add_transition &&
(GetIsolate()->context()->global_context()->object_function()->map() !=
map());
if (allow_map_transition) {
// Allocate new instance descriptors for the old map with map transition.
- ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
- Map::cast(new_map),
- array_type);
+ ElementsTransitionDescriptor desc(elements_transition_sentinel_name,
+ Map::cast(new_map),
+ elements_kind);
Object* new_descriptors;
MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
&desc,
@@ -2248,6 +2223,7 @@
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
trap = isolate->derived_has_trap();
}
@@ -2278,6 +2254,7 @@
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
trap = isolate->derived_set_trap();
}
@@ -2305,6 +2282,7 @@
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return Failure::Exception();
if (trap->IsUndefined()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
@@ -2347,6 +2325,7 @@
Handle<String> trap_name =
isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (isolate->has_pending_exception()) return NONE;
if (trap->IsUndefined()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
@@ -2373,9 +2352,13 @@
HandleScope scope(isolate);
Handle<JSProxy> self(this);
- isolate->factory()->BecomeJSObject(self);
+ if (IsJSFunctionProxy()) {
+ isolate->factory()->BecomeJSFunction(self);
+ // Code will be set on the JavaScript side.
+ } else {
+ isolate->factory()->BecomeJSObject(self);
+ }
ASSERT(self->IsJSObject());
- // TODO(rossberg): recognize function proxies.
}
@@ -2498,7 +2481,7 @@
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
}
case NULL_DESCRIPTOR:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
@@ -2586,7 +2569,7 @@
// if the value is a function.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case NULL_DESCRIPTOR:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
@@ -2867,7 +2850,7 @@
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
case INTERCEPTOR:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
break;
default:
UNREACHABLE();
@@ -5100,13 +5083,13 @@
}
-SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int offset,
- int length,
- int* length_return) {
+SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int offset,
+ int length,
+ int* length_return) {
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return SmartPointer<char>(NULL);
+ return SmartArrayPointer<char>(NULL);
}
Heap* heap = GetHeap();
@@ -5150,13 +5133,13 @@
character_position++;
}
result[utf8_byte_position] = 0;
- return SmartPointer<char>(result);
+ return SmartArrayPointer<char>(result);
}
-SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robust_flag,
- int* length_return) {
+SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robust_flag,
+ int* length_return) {
return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
}
@@ -5187,9 +5170,9 @@
}
-SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
+SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
- return SmartPointer<uc16>();
+ return SmartArrayPointer<uc16>();
}
Heap* heap = GetHeap();
@@ -5205,7 +5188,7 @@
result[i++] = character;
}
result[i] = 0;
- return SmartPointer<uc16>(result);
+ return SmartArrayPointer<uc16>(result);
}
@@ -6219,7 +6202,7 @@
DescriptorArray* descriptors = instance_descriptors();
for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
if (descriptors->GetType(i) == MAP_TRANSITION ||
- descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
+ descriptors->GetType(i) == ELEMENTS_TRANSITION ||
descriptors->GetType(i) == CONSTANT_TRANSITION) {
// Get target.
Map* target = Map::cast(descriptors->GetValue(i));
@@ -6262,7 +6245,7 @@
// non-live object.
PropertyDetails details(Smi::cast(contents->get(i + 1)));
if (details.type() == MAP_TRANSITION ||
- details.type() == EXTERNAL_ARRAY_TRANSITION ||
+ details.type() == ELEMENTS_TRANSITION ||
details.type() == CONSTANT_TRANSITION) {
Map* target = reinterpret_cast<Map*>(contents->get(i));
ASSERT(target->IsHeapObject());
@@ -6422,7 +6405,7 @@
void JSFunction::PrintName(FILE* out) {
- SmartPointer<char> name = shared()->DebugName()->ToCString();
+ SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
PrintF(out, "%s", *name);
}
@@ -7026,7 +7009,7 @@
JSFunction* function =
JSFunction::cast(LiteralArray()->get(function_id));
unsigned height = iterator.Next();
- PrintF(out, "{ast_id=%d, \nfunction=", ast_id);
+ PrintF(out, "{ast_id=%d, function=", ast_id);
function->PrintName(out);
PrintF(out, ", height=%u}", height);
break;
@@ -7151,7 +7134,7 @@
case HANDLER: return "HANDLER";
case INTERCEPTOR: return "INTERCEPTOR";
case MAP_TRANSITION: return "MAP_TRANSITION";
- case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
+ case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
}
@@ -7190,7 +7173,6 @@
if (is_inline_cache_stub()) {
PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
PrintExtraICState(out, kind(), extra_ic_state());
- PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
if (ic_state() == MONOMORPHIC) {
PrintF(out, "type = %s\n", PropertyType2String(type()));
}
@@ -7541,7 +7523,7 @@
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
if (value < 0) return ArrayLengthRangeError(GetHeap());
- JSObject::ElementsKind elements_kind = GetElementsKind();
+ ElementsKind elements_kind = GetElementsKind();
switch (elements_kind) {
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
@@ -10151,6 +10133,8 @@
// If the object is in dictionary mode, it is converted to fast elements
// mode.
MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
+ ASSERT(!HasExternalArrayElements());
+
Heap* heap = GetHeap();
if (HasDictionaryElements()) {
@@ -10180,9 +10164,6 @@
set_map(new_map);
set_elements(fast_elements);
- } else if (HasExternalArrayElements()) {
- // External arrays cannot have holes or undefined elements.
- return Smi::FromInt(ExternalArray::cast(elements())->length());
} else if (!HasFastDoubleElements()) {
Object* obj;
{ MaybeObject* maybe_obj = EnsureWritableFastElements();
diff --git a/src/objects.h b/src/objects.h
index 53ba981..d9c7a82 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -31,7 +31,7 @@
#include "allocation.h"
#include "builtins.h"
#include "list.h"
-#include "smart-pointer.h"
+#include "smart-array-pointer.h"
#include "unicode-inl.h"
#if V8_TARGET_ARCH_ARM
#include "arm/constants-arm.h"
@@ -135,6 +135,37 @@
namespace v8 {
namespace internal {
+enum ElementsKind {
+ // The "fast" kind for tagged values. Must be first to make it possible
+ // to efficiently check maps if they have fast elements.
+ FAST_ELEMENTS,
+
+ // The "fast" kind for unwrapped, non-tagged double values.
+ FAST_DOUBLE_ELEMENTS,
+
+ // The "slow" kind.
+ DICTIONARY_ELEMENTS,
+ NON_STRICT_ARGUMENTS_ELEMENTS,
+ // The "fast" kind for external arrays
+ EXTERNAL_BYTE_ELEMENTS,
+ EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
+ EXTERNAL_SHORT_ELEMENTS,
+ EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
+ EXTERNAL_INT_ELEMENTS,
+ EXTERNAL_UNSIGNED_INT_ELEMENTS,
+ EXTERNAL_FLOAT_ELEMENTS,
+ EXTERNAL_DOUBLE_ELEMENTS,
+ EXTERNAL_PIXEL_ELEMENTS,
+
+ // Derived constants from ElementsKind
+ FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
+ LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
+ FIRST_ELEMENTS_KIND = FAST_ELEMENTS,
+ LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS
+};
+
+static const int kElementsKindCount =
+ LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
// PropertyDetails captures type and attributes for a property.
// They are used both in property dictionaries and instance descriptors.
@@ -143,7 +174,7 @@
PropertyDetails(PropertyAttributes attributes,
PropertyType type,
int index = 0) {
- ASSERT(type != EXTERNAL_ARRAY_TRANSITION);
+ ASSERT(type != ELEMENTS_TRANSITION);
ASSERT(TypeField::is_valid(type));
ASSERT(AttributesField::is_valid(attributes));
ASSERT(StorageField::is_valid(index));
@@ -159,19 +190,19 @@
PropertyDetails(PropertyAttributes attributes,
PropertyType type,
- ExternalArrayType array_type) {
- ASSERT(type == EXTERNAL_ARRAY_TRANSITION);
+ ElementsKind elements_kind) {
+ ASSERT(type == ELEMENTS_TRANSITION);
ASSERT(TypeField::is_valid(type));
ASSERT(AttributesField::is_valid(attributes));
- ASSERT(StorageField::is_valid(static_cast<int>(array_type)));
+ ASSERT(StorageField::is_valid(static_cast<int>(elements_kind)));
value_ = TypeField::encode(type)
| AttributesField::encode(attributes)
- | StorageField::encode(static_cast<int>(array_type));
+ | StorageField::encode(static_cast<int>(elements_kind));
ASSERT(type == this->type());
ASSERT(attributes == this->attributes());
- ASSERT(array_type == this->array_type());
+ ASSERT(elements_kind == this->elements_kind());
}
// Conversion for storing details as Object*.
@@ -184,7 +215,7 @@
PropertyType t = type();
ASSERT(t != INTERCEPTOR);
return t == MAP_TRANSITION || t == CONSTANT_TRANSITION ||
- t == EXTERNAL_ARRAY_TRANSITION;
+ t == ELEMENTS_TRANSITION;
}
bool IsProperty() {
@@ -195,9 +226,9 @@
int index() { return StorageField::decode(value_); }
- ExternalArrayType array_type() {
- ASSERT(type() == EXTERNAL_ARRAY_TRANSITION);
- return static_cast<ExternalArrayType>(StorageField::decode(value_));
+ ElementsKind elements_kind() {
+ ASSERT(type() == ELEMENTS_TRANSITION);
+ return static_cast<ElementsKind>(StorageField::decode(value_));
}
inline PropertyDetails AsDeleted();
@@ -1463,38 +1494,6 @@
// caching.
class JSObject: public JSReceiver {
public:
- enum ElementsKind {
- // The "fast" kind for tagged values. Must be first to make it possible
- // to efficiently check maps if they have fast elements.
- FAST_ELEMENTS,
-
- // The "fast" kind for unwrapped, non-tagged double values.
- FAST_DOUBLE_ELEMENTS,
-
- // The "slow" kind.
- DICTIONARY_ELEMENTS,
- NON_STRICT_ARGUMENTS_ELEMENTS,
- // The "fast" kind for external arrays
- EXTERNAL_BYTE_ELEMENTS,
- EXTERNAL_UNSIGNED_BYTE_ELEMENTS,
- EXTERNAL_SHORT_ELEMENTS,
- EXTERNAL_UNSIGNED_SHORT_ELEMENTS,
- EXTERNAL_INT_ELEMENTS,
- EXTERNAL_UNSIGNED_INT_ELEMENTS,
- EXTERNAL_FLOAT_ELEMENTS,
- EXTERNAL_DOUBLE_ELEMENTS,
- EXTERNAL_PIXEL_ELEMENTS,
-
- // Derived constants from ElementsKind
- FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_BYTE_ELEMENTS,
- LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS,
- FIRST_ELEMENTS_KIND = FAST_ELEMENTS,
- LAST_ELEMENTS_KIND = EXTERNAL_PIXEL_ELEMENTS
- };
-
- static const int kElementsKindCount =
- LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
-
// [properties]: Backing storage for properties.
// properties is a FixedArray in the fast case and a Dictionary in the
// slow case.
@@ -3154,7 +3153,6 @@
// raised rather than being silently ignored.
class ExternalArray: public FixedArrayBase {
public:
-
inline bool is_the_hole(int index) { return false; }
// [external_pointer]: The pointer to the external memory area backing this
@@ -3655,7 +3653,6 @@
inline Kind kind();
inline InlineCacheState ic_state(); // Only valid for IC stubs.
inline ExtraICState extra_ic_state(); // Only valid for IC stubs.
- inline InLoopFlag ic_in_loop(); // Only valid for IC stubs.
inline PropertyType type(); // Only valid for monomorphic IC stubs.
inline int arguments_count(); // Only valid for call IC stubs.
@@ -3685,6 +3682,11 @@
inline bool has_deoptimization_support();
inline void set_has_deoptimization_support(bool value);
+ // [has_debug_break_slots]: For FUNCTION kind, tells if it has
+ // been compiled with debug break slots.
+ inline bool has_debug_break_slots();
+ inline void set_has_debug_break_slots(bool value);
+
// [allow_osr_at_loop_nesting_level]: For FUNCTION kind, tells for
// how long the function has been marked for OSR and therefore which
// level of loop nesting we are willing to do on-stack replacement
@@ -3743,7 +3745,6 @@
// Flags operations.
static inline Flags ComputeFlags(
Kind kind,
- InLoopFlag in_loop = NOT_IN_LOOP,
InlineCacheState ic_state = UNINITIALIZED,
ExtraICState extra_ic_state = kNoExtraICState,
PropertyType type = NORMAL,
@@ -3755,16 +3756,15 @@
PropertyType type,
ExtraICState extra_ic_state = kNoExtraICState,
InlineCacheHolderFlag holder = OWN_MAP,
- InLoopFlag in_loop = NOT_IN_LOOP,
int argc = -1);
- static inline Kind ExtractKindFromFlags(Flags flags);
static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
- static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
- static inline InLoopFlag ExtractICInLoopFromFlags(Flags flags);
static inline PropertyType ExtractTypeFromFlags(Flags flags);
- static inline int ExtractArgumentsCountFromFlags(Flags flags);
+ static inline Kind ExtractKindFromFlags(Flags flags);
static inline InlineCacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
+ static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
+ static inline int ExtractArgumentsCountFromFlags(Flags flags);
+
static inline Flags RemoveTypeFromFlags(Flags flags);
// Convert a target address into a code object.
@@ -3875,34 +3875,32 @@
static const int kBinaryOpTypeOffset = kStubMajorKeyOffset + 1;
static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
static const int kToBooleanTypeOffset = kStubMajorKeyOffset + 1;
- static const int kHasDeoptimizationSupportOffset = kOptimizableOffset + 1;
+
+ static const int kFullCodeFlags = kOptimizableOffset + 1;
+ class FullCodeFlagsHasDeoptimizationSupportField:
+ public BitField<bool, 0, 1> {}; // NOLINT
+ class FullCodeFlagsHasDebugBreakSlotsField: public BitField<bool, 1, 1> {};
static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1;
- static const int kAllowOSRAtLoopNestingLevelOffset =
- kHasDeoptimizationSupportOffset + 1;
+
+ static const int kAllowOSRAtLoopNestingLevelOffset = kFullCodeFlags + 1;
static const int kSafepointTableOffsetOffset = kStackSlotsOffset + kIntSize;
static const int kStackCheckTableOffsetOffset = kStackSlotsOffset + kIntSize;
- // Flags layout.
- static const int kFlagsICStateShift = 0;
- static const int kFlagsICInLoopShift = 3;
- static const int kFlagsTypeShift = 4;
- static const int kFlagsKindShift = 8;
- static const int kFlagsICHolderShift = 12;
- static const int kFlagsExtraICStateShift = 13;
- static const int kFlagsArgumentsCountShift = 15;
+ // Flags layout. BitField<type, shift, size>.
+ class ICStateField: public BitField<InlineCacheState, 0, 3> {};
+ class TypeField: public BitField<PropertyType, 3, 4> {};
+ class KindField: public BitField<Kind, 7, 4> {};
+ class CacheHolderField: public BitField<InlineCacheHolderFlag, 11, 1> {};
+ class ExtraICStateField: public BitField<ExtraICState, 12, 2> {};
- static const int kFlagsICStateMask = 0x00000007; // 00000000111
- static const int kFlagsICInLoopMask = 0x00000008; // 00000001000
- static const int kFlagsTypeMask = 0x000000F0; // 00001110000
- static const int kFlagsKindMask = 0x00000F00; // 11110000000
- static const int kFlagsCacheInPrototypeMapMask = 0x00001000;
- static const int kFlagsExtraICStateMask = 0x00006000;
- static const int kFlagsArgumentsCountMask = 0xFFFF8000;
+ // Signed field cannot be encoded using the BitField class.
+ static const int kArgumentsCountShift = 14;
+ static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1);
static const int kFlagsNotUsedInLookup =
- (kFlagsICInLoopMask | kFlagsTypeMask | kFlagsCacheInPrototypeMapMask);
+ TypeField::kMask | CacheHolderField::kMask;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
@@ -4021,37 +4019,37 @@
inline void set_is_extensible(bool value);
inline bool is_extensible();
- inline void set_elements_kind(JSObject::ElementsKind elements_kind) {
- ASSERT(elements_kind < JSObject::kElementsKindCount);
- ASSERT(JSObject::kElementsKindCount <= (1 << kElementsKindBitCount));
+ inline void set_elements_kind(ElementsKind elements_kind) {
+ ASSERT(elements_kind < kElementsKindCount);
+ ASSERT(kElementsKindCount <= (1 << kElementsKindBitCount));
set_bit_field2((bit_field2() & ~kElementsKindMask) |
(elements_kind << kElementsKindShift));
ASSERT(this->elements_kind() == elements_kind);
}
- inline JSObject::ElementsKind elements_kind() {
- return static_cast<JSObject::ElementsKind>(
+ inline ElementsKind elements_kind() {
+ return static_cast<ElementsKind>(
(bit_field2() & kElementsKindMask) >> kElementsKindShift);
}
// Tells whether the instance has fast elements.
// Equivalent to instance->GetElementsKind() == FAST_ELEMENTS.
inline bool has_fast_elements() {
- return elements_kind() == JSObject::FAST_ELEMENTS;
+ return elements_kind() == FAST_ELEMENTS;
}
inline bool has_fast_double_elements() {
- return elements_kind() == JSObject::FAST_DOUBLE_ELEMENTS;
+ return elements_kind() == FAST_DOUBLE_ELEMENTS;
}
inline bool has_external_array_elements() {
- JSObject::ElementsKind kind(elements_kind());
- return kind >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
- kind <= JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
+ ElementsKind kind(elements_kind());
+ return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
+ kind <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND;
}
inline bool has_dictionary_elements() {
- return elements_kind() == JSObject::DICTIONARY_ELEMENTS;
+ return elements_kind() == DICTIONARY_ELEMENTS;
}
// Tells whether the map is attached to SharedFunctionInfo
@@ -4156,9 +4154,9 @@
MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap();
// Returns a new map with all transitions dropped from the descriptors and the
- // ElementsKind set to one of the value corresponding to array_type.
- MUST_USE_RESULT MaybeObject* GetExternalArrayElementsMap(
- ExternalArrayType array_type,
+ // ElementsKind set.
+ MUST_USE_RESULT MaybeObject* GetElementsTransitionMap(
+ ElementsKind elements_kind,
bool safe_to_add_transition);
// Returns the property index for name (only valid for FAST MODE).
@@ -4323,7 +4321,7 @@
static const int kElementsKindMask = (-1 << kElementsKindShift) &
((1 << (kElementsKindShift + kElementsKindBitCount)) - 1);
static const int8_t kMaximumBitField2FastElementValue = static_cast<int8_t>(
- (JSObject::FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1;
+ (FAST_ELEMENTS + 1) << Map::kElementsKindShift) - 1;
// Bit positions for bit field 3
static const int kIsShared = 0;
@@ -4737,7 +4735,7 @@
DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
// Indicates whether the function is a native function.
- // These needs special threatment in .call and .apply since
+ // These needs special treatment in .call and .apply since
// null passed as the receiver should not be translated to the
// global object.
DECL_BOOLEAN_ACCESSORS(native)
@@ -5004,7 +5002,7 @@
// [prototype_or_initial_map]:
DECL_ACCESSORS(prototype_or_initial_map, Object)
- // [shared_function_info]: The information about the function that
+ // [shared]: The information about the function that
// can be shared by instances.
DECL_ACCESSORS(shared, SharedFunctionInfo)
@@ -5981,12 +5979,12 @@
// ROBUST_STRING_TRAVERSAL invokes behaviour that is robust This means it
// handles unexpected data without causing assert failures and it does not
// do any heap allocations. This is useful when printing stack traces.
- SmartPointer<char> ToCString(AllowNullsFlag allow_nulls,
- RobustnessFlag robustness_flag,
- int offset,
- int length,
- int* length_output = 0);
- SmartPointer<char> ToCString(
+ SmartArrayPointer<char> ToCString(AllowNullsFlag allow_nulls,
+ RobustnessFlag robustness_flag,
+ int offset,
+ int length,
+ int* length_output = 0);
+ SmartArrayPointer<char> ToCString(
AllowNullsFlag allow_nulls = DISALLOW_NULLS,
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL,
int* length_output = 0);
@@ -5999,7 +5997,7 @@
// ROBUST_STRING_TRAVERSAL invokes behaviour that is robust This means it
// handles unexpected data without causing assert failures and it does not
// do any heap allocations. This is useful when printing stack traces.
- SmartPointer<uc16> ToWideCString(
+ SmartArrayPointer<uc16> ToWideCString(
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL);
// Tells whether the hash code has been computed.
@@ -6409,7 +6407,6 @@
// - truncating sliced string to enable otherwise unneeded parent to be GC'ed.
class SlicedString: public String {
public:
-
inline String* parent();
inline void set_parent(String* parent);
inline int offset();
@@ -6722,9 +6719,6 @@
// [handler]: The handler property.
DECL_ACCESSORS(handler, Object)
- // [padding]: The padding slot (unused, see below).
- DECL_ACCESSORS(padding, Object)
-
// Casting.
static inline JSProxy* cast(Object* obj);
@@ -6748,6 +6742,9 @@
// Turn this into an (empty) JSObject.
void Fix();
+ // Initializes the body after the handler slot.
+ inline void InitializeBody(int object_size, Object* value);
+
// Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSProxyPrint() {
@@ -6764,9 +6761,11 @@
// upon freeze.
static const int kHandlerOffset = HeapObject::kHeaderSize;
static const int kPaddingOffset = kHandlerOffset + kPointerSize;
- static const int kSize = kPaddingOffset + kPointerSize;
+ static const int kSize = JSObject::kHeaderSize;
+ static const int kHeaderSize = kPaddingOffset;
+ static const int kPaddingSize = kSize - kPaddingOffset;
- STATIC_CHECK(kSize == JSObject::kHeaderSize);
+ STATIC_CHECK(kPaddingSize >= 0);
typedef FixedBodyDescriptor<kHandlerOffset,
kHandlerOffset + kPointerSize,
@@ -6777,12 +6776,41 @@
};
-// TODO(rossberg): Only a stub for now.
class JSFunctionProxy: public JSProxy {
public:
+ // [call_trap]: The call trap.
+ DECL_ACCESSORS(call_trap, Object)
+
+ // [construct_trap]: The construct trap.
+ DECL_ACCESSORS(construct_trap, Object)
+
// Casting.
static inline JSFunctionProxy* cast(Object* obj);
+ // Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSFunctionProxyPrint() {
+ JSFunctionProxyPrint(stdout);
+ }
+ void JSFunctionProxyPrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSFunctionProxyVerify();
+#endif
+
+ // Layout description.
+ static const int kCallTrapOffset = kHandlerOffset + kPointerSize;
+ static const int kConstructTrapOffset = kCallTrapOffset + kPointerSize;
+ static const int kPaddingOffset = kConstructTrapOffset + kPointerSize;
+ static const int kSize = JSFunction::kSize;
+ static const int kPaddingSize = kSize - kPaddingOffset;
+
+ STATIC_CHECK(kPaddingSize >= 0);
+
+ typedef FixedBodyDescriptor<kHandlerOffset,
+ kConstructTrapOffset + kPointerSize,
+ kSize> BodyDescriptor;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSFunctionProxy);
};
diff --git a/src/parser.cc b/src/parser.cc
index f8c7c41..f9500c4 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -30,6 +30,7 @@
#include "api.h"
#include "ast-inl.h"
#include "bootstrapper.h"
+#include "char-predicates-inl.h"
#include "codegen.h"
#include "compiler.h"
#include "func-name-inferrer.h"
@@ -38,6 +39,7 @@
#include "platform.h"
#include "preparser.h"
#include "runtime.h"
+#include "scanner-character-streams.h"
#include "scopeinfo.h"
#include "string-stream.h"
@@ -532,7 +534,7 @@
parser->top_scope_ = scope;
parser->lexical_scope_ = this;
parser->with_nesting_level_ = 0;
- isolate->set_ast_node_id(AstNode::kFunctionEntryId + 1);
+ isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
}
@@ -647,6 +649,11 @@
if (ok && top_scope_->is_strict_mode()) {
CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
}
+
+ if (ok && harmony_block_scoping_) {
+ CheckConflictingVarDeclarations(scope, &ok);
+ }
+
if (ok) {
result = new(zone()) FunctionLiteral(
isolate(),
@@ -950,18 +957,17 @@
};
-// A ThisNamedPropertyAssignmentFinder finds and marks statements of the form
+// A ThisNamedPropertyAssigmentFinder finds and marks statements of the form
// this.x = ...;, where x is a named property. It also determines whether a
// function contains only assignments of this type.
-class ThisNamedPropertyAssignmentFinder : public ParserFinder {
+class ThisNamedPropertyAssigmentFinder : public ParserFinder {
public:
- explicit ThisNamedPropertyAssignmentFinder(Isolate* isolate)
+ explicit ThisNamedPropertyAssigmentFinder(Isolate* isolate)
: isolate_(isolate),
only_simple_this_property_assignments_(true),
- names_(0),
- assigned_arguments_(0),
- assigned_constants_(0) {
- }
+ names_(NULL),
+ assigned_arguments_(NULL),
+ assigned_constants_(NULL) {}
void Update(Scope* scope, Statement* stat) {
// Bail out if function already has property assignment that are
@@ -988,17 +994,19 @@
// Returns a fixed array containing three elements for each assignment of the
// form this.x = y;
Handle<FixedArray> GetThisPropertyAssignments() {
- if (names_.is_empty()) {
+ if (names_ == NULL) {
return isolate_->factory()->empty_fixed_array();
}
- ASSERT_EQ(names_.length(), assigned_arguments_.length());
- ASSERT_EQ(names_.length(), assigned_constants_.length());
+ ASSERT(names_ != NULL);
+ ASSERT(assigned_arguments_ != NULL);
+ ASSERT_EQ(names_->length(), assigned_arguments_->length());
+ ASSERT_EQ(names_->length(), assigned_constants_->length());
Handle<FixedArray> assignments =
- isolate_->factory()->NewFixedArray(names_.length() * 3);
- for (int i = 0; i < names_.length(); ++i) {
- assignments->set(i * 3, *names_[i]);
- assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_[i]));
- assignments->set(i * 3 + 2, *assigned_constants_[i]);
+ isolate_->factory()->NewFixedArray(names_->length() * 3);
+ for (int i = 0; i < names_->length(); i++) {
+ assignments->set(i * 3, *names_->at(i));
+ assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_->at(i)));
+ assignments->set(i * 3 + 2, *assigned_constants_->at(i));
}
return assignments;
}
@@ -1055,37 +1063,18 @@
AssignmentFromSomethingElse();
}
-
-
-
- // We will potentially reorder the property assignments, so they must be
- // simple enough that the ordering does not matter.
void AssignmentFromParameter(Handle<String> name, int index) {
- EnsureInitialized();
- for (int i = 0; i < names_.length(); ++i) {
- if (name->Equals(*names_[i])) {
- assigned_arguments_[i] = index;
- assigned_constants_[i] = isolate_->factory()->undefined_value();
- return;
- }
- }
- names_.Add(name);
- assigned_arguments_.Add(index);
- assigned_constants_.Add(isolate_->factory()->undefined_value());
+ EnsureAllocation();
+ names_->Add(name);
+ assigned_arguments_->Add(index);
+ assigned_constants_->Add(isolate_->factory()->undefined_value());
}
void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
- EnsureInitialized();
- for (int i = 0; i < names_.length(); ++i) {
- if (name->Equals(*names_[i])) {
- assigned_arguments_[i] = -1;
- assigned_constants_[i] = value;
- return;
- }
- }
- names_.Add(name);
- assigned_arguments_.Add(-1);
- assigned_constants_.Add(value);
+ EnsureAllocation();
+ names_->Add(name);
+ assigned_arguments_->Add(-1);
+ assigned_constants_->Add(value);
}
void AssignmentFromSomethingElse() {
@@ -1093,21 +1082,22 @@
only_simple_this_property_assignments_ = false;
}
- void EnsureInitialized() {
- if (names_.capacity() == 0) {
- ASSERT(assigned_arguments_.capacity() == 0);
- ASSERT(assigned_constants_.capacity() == 0);
- names_.Initialize(4);
- assigned_arguments_.Initialize(4);
- assigned_constants_.Initialize(4);
+ void EnsureAllocation() {
+ if (names_ == NULL) {
+ ASSERT(assigned_arguments_ == NULL);
+ ASSERT(assigned_constants_ == NULL);
+ Zone* zone = isolate_->zone();
+ names_ = new(zone) ZoneStringList(4);
+ assigned_arguments_ = new(zone) ZoneList<int>(4);
+ assigned_constants_ = new(zone) ZoneObjectList(4);
}
}
Isolate* isolate_;
bool only_simple_this_property_assignments_;
- ZoneStringList names_;
- ZoneList<int> assigned_arguments_;
- ZoneObjectList assigned_constants_;
+ ZoneStringList* names_;
+ ZoneList<int>* assigned_arguments_;
+ ZoneObjectList* assigned_constants_;
};
@@ -1144,7 +1134,7 @@
ASSERT(processor != NULL);
InitializationBlockFinder block_finder(top_scope_, target_stack_);
- ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate());
+ ThisNamedPropertyAssigmentFinder this_property_assignment_finder(isolate());
bool directive_prologue = true; // Parsing directive prologue.
while (peek() != end_token) {
@@ -1360,14 +1350,32 @@
// Declare the name.
var = declaration_scope->DeclareLocal(name, mode);
} else {
- // The name was declared before; check for conflicting re-declarations.
- // We have a conflict if either of the declarations is not a var. There
- // is similar code in runtime.cc in the Declare functions.
+ // The name was declared in this scope before; check for conflicting
+ // re-declarations. We have a conflict if either of the declarations is
+ // not a var. There is similar code in runtime.cc in the Declare
+ // functions. The function CheckNonConflictingScope checks for conflicting
+ // var and let bindings from different scopes whereas this is a check for
+ // conflicting declarations within the same scope. This check also covers
+ //
+ // function () { let x; { var x; } }
+ //
+ // because the var declaration is hoisted to the function scope where 'x'
+ // is already bound.
if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) {
// We only have vars, consts and lets in declarations.
ASSERT(var->mode() == Variable::VAR ||
var->mode() == Variable::CONST ||
var->mode() == Variable::LET);
+ if (harmony_block_scoping_) {
+ // In harmony mode we treat re-declarations as early errors. See
+ // ES5 16 for a definition of early errors.
+ SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
+ const char* elms[2] = { "Variable", *c_string };
+ Vector<const char*> args(elms, 2);
+ ReportMessage("redeclaration", args);
+ *ok = false;
+ return NULL;
+ }
const char* type = (var->mode() == Variable::VAR) ? "var" :
(var->mode() == Variable::CONST) ? "const" : "let";
Handle<String> type_string =
@@ -1396,8 +1404,10 @@
// semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls.
- VariableProxy* proxy = declaration_scope->NewUnresolved(name, false);
- declaration_scope->AddDeclaration(new(zone()) Declaration(proxy, mode, fun));
+ VariableProxy* proxy = declaration_scope->NewUnresolved(
+ name, false, scanner().location().beg_pos);
+ declaration_scope->AddDeclaration(
+ new(zone()) Declaration(proxy, mode, fun, top_scope_));
// For global const variables we bind the proxy to a variable.
if (mode == Variable::CONST && declaration_scope->is_global_scope()) {
@@ -1551,9 +1561,6 @@
Scope* block_scope = NewScope(top_scope_,
Scope::BLOCK_SCOPE,
inside_with());
- body->set_block_scope(block_scope);
- block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(),
- Variable::VAR);
if (top_scope_->is_strict_mode()) {
block_scope->EnableStrictMode();
}
@@ -1576,21 +1583,11 @@
}
}
Expect(Token::RBRACE, CHECK_OK);
-
- // Create exit block.
- Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
- exit->AddStatement(new(zone()) ExitContextStatement());
-
- // Create a try-finally statement.
- TryFinallyStatement* try_finally =
- new(zone()) TryFinallyStatement(body, exit);
- try_finally->set_escaping_targets(collector.targets());
top_scope_ = saved_scope;
- // Create a result block.
- Block* result = new(zone()) Block(isolate(), NULL, 1, false);
- result->AddStatement(try_finally);
- return result;
+ block_scope = block_scope->FinalizeBlockScope();
+ body->set_block_scope(block_scope);
+ return body;
}
@@ -1839,18 +1836,21 @@
block->AddStatement(new(zone()) ExpressionStatement(initialize));
}
- // Add an assignment node to the initialization statement block if
- // we still have a pending initialization value. We must distinguish
- // between variables and constants: Variable initializations are simply
+ // Add an assignment node to the initialization statement block if we still
+ // have a pending initialization value. We must distinguish between
+ // different kinds of declarations: 'var' initializations are simply
// assignments (with all the consequences if they are inside a 'with'
// statement - they may change a 'with' object property). Constant
// initializations always assign to the declared constant which is
// always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the start context
// for constant lookups is always the function context, while it is
- // the top context for variables). Sigh...
+ // the top context for var declared variables). Sigh...
+ // For 'let' declared variables the initialization is in the same scope
+ // as the declaration. Thus dynamic lookups are unnecessary even if the
+ // block scope is inside a with.
if (value != NULL) {
- bool in_with = is_const ? false : inside_with();
+ bool in_with = mode == Variable::VAR ? inside_with() : false;
VariableProxy* proxy =
initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment =
@@ -1904,7 +1904,7 @@
// structured. However, these are probably changes we want to
// make later anyway so we should go back and fix this then.
if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
- SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> c_string = label->ToCString(DISALLOW_NULLS);
const char* elms[2] = { "Label", *c_string };
Vector<const char*> args(elms, 2);
ReportMessage("redeclaration", args);
@@ -2219,22 +2219,19 @@
Expect(Token::RPAREN, CHECK_OK);
if (peek() == Token::LBRACE) {
- // Rewrite the catch body { B } to a block:
- // { { B } ExitContext; }.
Target target(&this->target_stack_, &catch_collector);
catch_scope = NewScope(top_scope_, Scope::CATCH_SCOPE, inside_with());
if (top_scope_->is_strict_mode()) {
catch_scope->EnableStrictMode();
}
- catch_variable = catch_scope->DeclareLocal(name, Variable::VAR);
- catch_block = new(zone()) Block(isolate(), NULL, 2, false);
+ Variable::Mode mode = harmony_block_scoping_
+ ? Variable::LET : Variable::VAR;
+ catch_variable = catch_scope->DeclareLocal(name, mode);
Scope* saved_scope = top_scope_;
top_scope_ = catch_scope;
- Block* catch_body = ParseBlock(NULL, CHECK_OK);
+ catch_block = ParseBlock(NULL, CHECK_OK);
top_scope_ = saved_scope;
- catch_block->AddStatement(catch_body);
- catch_block->AddStatement(new(zone()) ExitContextStatement());
} else {
Expect(Token::LBRACE, CHECK_OK);
}
@@ -3013,7 +3010,7 @@
void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
- SmartPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
const char* element[1] = { *name_string };
ReportMessage("invalid_preparser_data",
Vector<const char*>(element, 1));
@@ -3757,7 +3754,10 @@
reserved_loc = scanner().location();
}
- top_scope_->DeclareParameter(param_name);
+ top_scope_->DeclareParameter(param_name,
+ harmony_block_scoping_
+ ? Variable::LET
+ : Variable::VAR);
num_parameters++;
if (num_parameters > kMaxNumFunctionParameters) {
ReportMessageAt(scanner().location(), "too_many_parameters",
@@ -3884,6 +3884,10 @@
}
}
+ if (harmony_block_scoping_) {
+ CheckConflictingVarDeclarations(scope, CHECK_OK);
+ }
+
FunctionLiteral* function_literal =
new(zone()) FunctionLiteral(isolate(),
function_name,
@@ -4090,6 +4094,25 @@
}
+void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
+ Declaration* decl = scope->CheckConflictingVarDeclarations();
+ if (decl != NULL) {
+ // In harmony mode we treat conflicting variable bindinds as early
+ // errors. See ES5 16 for a definition of early errors.
+ Handle<String> name = decl->proxy()->name();
+ SmartArrayPointer<char> c_string = name->ToCString(DISALLOW_NULLS);
+ const char* elms[2] = { "Variable", *c_string };
+ Vector<const char*> args(elms, 2);
+ int position = decl->proxy()->position();
+ Scanner::Location location = position == RelocInfo::kNoPosition
+ ? Scanner::Location::invalid()
+ : Scanner::Location(position, position + 1);
+ ReportMessageAt(location, "redeclaration", args);
+ *ok = false;
+ }
+}
+
+
// This function reads an identifier name and determines whether or not it
// is 'get' or 'set'.
Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
diff --git a/src/parser.h b/src/parser.h
index 686dac8..3312f2f 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -30,10 +30,9 @@
#include "allocation.h"
#include "ast.h"
-#include "scanner.h"
-#include "scopes.h"
#include "preparse-data-format.h"
#include "preparse-data.h"
+#include "scopes.h"
namespace v8 {
namespace internal {
@@ -645,6 +644,17 @@
// Strict mode octal literal validation.
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
+ // For harmony block scoping mode: Check if the scope has conflicting var/let
+ // declarations from different scopes. It covers for example
+ //
+ // function f() { { { var x; } let x; } }
+ // function g() { { var x; let x; } }
+ //
+ // The var declarations are hoisted to the function scope, but originate from
+ // a scope where the name has also been let bound or the var declaration is
+ // hoisted over such a scope.
+ void CheckConflictingVarDeclarations(Scope* scope, bool* ok);
+
// Parser support
VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
FunctionLiteral* fun,
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index 85a5e4f..a72f5da 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -474,7 +474,6 @@
class CygwinMutex : public Mutex {
public:
-
CygwinMutex() {
pthread_mutexattr_t attrs;
memset(&attrs, 0, sizeof(attrs));
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 9d9f1b7..685ec3c 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -471,7 +471,6 @@
class FreeBSDMutex : public Mutex {
public:
-
FreeBSDMutex() {
pthread_mutexattr_t attrs;
int result = pthread_mutexattr_init(&attrs);
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 362bf47..b152dae 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -130,13 +130,7 @@
uint64_t OS::CpuFeaturesImpliedByPlatform() {
-#if(defined(__mips_hard_float) && __mips_hard_float != 0)
- // Here gcc is telling us that we are on an MIPS and gcc is assuming that we
- // have FPU instructions. If gcc can assume it then so can we.
- return 1u << FPU;
-#else
return 0; // Linux runs on anything.
-#endif
}
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index be6e157..6be941a 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -558,7 +558,6 @@
class MacOSMutex : public Mutex {
public:
-
MacOSMutex() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index 1e79f10..035d394 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -460,7 +460,6 @@
class SolarisMutex : public Mutex {
public:
-
SolarisMutex() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index e5df5ff..97788e2 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -35,76 +35,8 @@
#include "platform.h"
#include "vm-state-inl.h"
-// Extra POSIX/ANSI routines for Win32 when when using Visual Studio C++. Please
-// refer to The Open Group Base Specification for specification of the correct
-// semantics for these functions.
-// (http://www.opengroup.org/onlinepubs/000095399/)
#ifdef _MSC_VER
-namespace v8 {
-namespace internal {
-
-// Test for finite value - usually defined in math.h
-int isfinite(double x) {
- return _finite(x);
-}
-
-} // namespace v8
-} // namespace internal
-
-// Test for a NaN (not a number) value - usually defined in math.h
-int isnan(double x) {
- return _isnan(x);
-}
-
-
-// Test for infinity - usually defined in math.h
-int isinf(double x) {
- return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0;
-}
-
-
-// Test if x is less than y and both nominal - usually defined in math.h
-int isless(double x, double y) {
- return isnan(x) || isnan(y) ? 0 : x < y;
-}
-
-
-// Test if x is greater than y and both nominal - usually defined in math.h
-int isgreater(double x, double y) {
- return isnan(x) || isnan(y) ? 0 : x > y;
-}
-
-
-// Classify floating point number - usually defined in math.h
-int fpclassify(double x) {
- // Use the MS-specific _fpclass() for classification.
- int flags = _fpclass(x);
-
- // Determine class. We cannot use a switch statement because
- // the _FPCLASS_ constants are defined as flags.
- if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL;
- if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO;
- if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL;
- if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE;
-
- // All cases should be covered by the code above.
- ASSERT(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN));
- return FP_NAN;
-}
-
-
-// Test sign - usually defined in math.h
-int signbit(double x) {
- // We need to take care of the special case of both positive
- // and negative versions of zero.
- if (x == 0)
- return _fpclass(x) & _FPCLASS_NZ;
- else
- return x < 0;
-}
-
-
// Case-insensitive bounded string comparisons. Use stricmp() on Win32. Usually
// defined in strings.h.
int strncasecmp(const char* s1, const char* s2, int n) {
@@ -1367,7 +1299,7 @@
// Try to locate a symbol for this frame.
DWORD64 symbol_displacement;
- SmartPointer<IMAGEHLP_SYMBOL64> symbol(
+ SmartArrayPointer<IMAGEHLP_SYMBOL64> symbol(
NewArray<IMAGEHLP_SYMBOL64>(kStackWalkMaxNameLen));
if (symbol.is_empty()) return kStackWalkError; // Out of memory.
memset(*symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + kStackWalkMaxNameLen);
diff --git a/src/platform.h b/src/platform.h
index 6b2348c..034fe34 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -44,53 +44,12 @@
#ifndef V8_PLATFORM_H_
#define V8_PLATFORM_H_
-#define V8_INFINITY INFINITY
-
-// Windows specific stuff.
-#ifdef WIN32
-
-// Microsoft Visual C++ specific stuff.
-#ifdef _MSC_VER
-
-enum {
- FP_NAN,
- FP_INFINITE,
- FP_ZERO,
- FP_SUBNORMAL,
- FP_NORMAL
-};
-
-#undef V8_INFINITY
-#define V8_INFINITY HUGE_VAL
-
-namespace v8 {
-namespace internal {
-int isfinite(double x);
-} }
-int isnan(double x);
-int isinf(double x);
-int isless(double x, double y);
-int isgreater(double x, double y);
-int fpclassify(double x);
-int signbit(double x);
-
-int strncasecmp(const char* s1, const char* s2, int n);
-
-#endif // _MSC_VER
-
-// Random is missing on both Visual Studio and MinGW.
-int random();
-
-#endif // WIN32
-
-
#ifdef __sun
# ifndef signbit
int signbit(double x);
# endif
#endif
-
// GCC specific stuff
#ifdef __GNUC__
@@ -99,20 +58,26 @@
#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
-// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
-// warning flag and certain versions of GCC due to a bug:
-// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
-// For now, we use the more involved template-based version from <limits>, but
-// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
-// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
-#if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100
-#include <limits>
-#undef V8_INFINITY
-#define V8_INFINITY std::numeric_limits<double>::infinity()
-#endif
-
#endif // __GNUC__
+
+// Windows specific stuff.
+#ifdef WIN32
+
+// Microsoft Visual C++ specific stuff.
+#ifdef _MSC_VER
+
+#include "win32-math.h"
+
+int strncasecmp(const char* s1, const char* s2, int n);
+
+#endif // _MSC_VER
+
+// Random is missing on both Visual Studio and MinGW.
+int random();
+
+#endif // WIN32
+
#include "atomicops.h"
#include "platform-tls.h"
#include "utils.h"
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
index 80656d5..899489e 100644
--- a/src/preparser-api.cc
+++ b/src/preparser-api.cc
@@ -25,15 +25,19 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#ifdef _MSC_VER
+#define V8_WIN32_LEAN_AND_MEAN
+#include "win32-headers.h"
+#endif
+
#include "../include/v8-preparser.h"
#include "globals.h"
-#include "flags.h"
#include "checks.h"
#include "allocation.h"
#include "utils.h"
#include "list.h"
-#include "scanner-base.h"
+#include "hashmap.h"
#include "preparse-data-format.h"
#include "preparse-data.h"
#include "preparser.h"
diff --git a/src/preparser.cc b/src/preparser.cc
index 1a3dd73..47d21ba 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -25,22 +25,31 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "../include/v8stdint.h"
-#include "unicode.h"
-#include "globals.h"
-#include "checks.h"
-#include "allocation.h"
-#include "utils.h"
-#include "list.h"
+#include <math.h>
-#include "scanner-base.h"
+#include "../include/v8stdint.h"
+
+#include "allocation.h"
+#include "checks.h"
+#include "conversions.h"
+#include "conversions-inl.h"
+#include "globals.h"
+#include "hashmap.h"
+#include "list.h"
#include "preparse-data-format.h"
#include "preparse-data.h"
#include "preparser.h"
-
-#include "conversions-inl.h"
+#include "unicode.h"
+#include "utils.h"
namespace v8 {
+
+#ifdef _MSC_VER
+// Usually defined in math.h, but not in MSVC.
+// Abstracted to work
+int isfinite(double value);
+#endif
+
namespace preparser {
// Preparsing checks a JavaScript program and emits preparse-data that helps
@@ -68,27 +77,22 @@
// Four of the tokens are treated specially
switch (token) {
case i::Token::EOS:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_eos", NULL);
+ return ReportMessageAt(source_location, "unexpected_eos", NULL);
case i::Token::NUMBER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_number", NULL);
+ return ReportMessageAt(source_location, "unexpected_token_number", NULL);
case i::Token::STRING:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_string", NULL);
+ return ReportMessageAt(source_location, "unexpected_token_string", NULL);
case i::Token::IDENTIFIER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ return ReportMessageAt(source_location,
"unexpected_token_identifier", NULL);
case i::Token::FUTURE_RESERVED_WORD:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_reserved", NULL);
+ return ReportMessageAt(source_location, "unexpected_reserved", NULL);
case i::Token::FUTURE_STRICT_RESERVED_WORD:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ return ReportMessageAt(source_location,
"unexpected_strict_reserved", NULL);
default:
const char* name = i::Token::String(token);
- ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token", name);
+ ReportMessageAt(source_location, "unexpected_token", name);
}
}
@@ -98,7 +102,7 @@
void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
i::Scanner::Location octal = scanner_->octal_position();
if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
- ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL);
+ ReportMessageAt(octal, "strict_octal_literal", NULL);
scanner_->clear_octal_position();
*ok = false;
}
@@ -251,7 +255,7 @@
if (identifier.IsFutureStrictReserved()) {
type = "strict_reserved_word";
}
- ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ ReportMessageAt(location, type, NULL);
*ok = false;
}
return Statement::FunctionDeclaration();
@@ -313,8 +317,7 @@
} else if (peek() == i::Token::CONST) {
if (strict_mode()) {
i::Scanner::Location location = scanner_->peek_location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "strict_const", NULL);
+ ReportMessageAt(location, "strict_const", NULL);
*ok = false;
return Statement::Default();
}
@@ -475,8 +478,7 @@
Expect(i::Token::WITH, CHECK_OK);
if (strict_mode()) {
i::Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "strict_mode_with", NULL);
+ ReportMessageAt(location, "strict_mode_with", NULL);
*ok = false;
return Statement::Default();
}
@@ -612,8 +614,7 @@
Expect(i::Token::THROW, CHECK_OK);
if (scanner_->HasAnyLineTerminatorBeforeNext()) {
i::JavaScriptScanner::Location pos = scanner_->location();
- ReportMessageAt(pos.beg_pos, pos.end_pos,
- "newline_after_throw", NULL);
+ ReportMessageAt(pos, "newline_after_throw", NULL);
*ok = false;
return Statement::Default();
}
@@ -1025,8 +1026,7 @@
if (strict_mode()) {
Next();
i::Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "strict_reserved_word", NULL);
+ ReportMessageAt(location, "strict_reserved_word", NULL);
*ok = false;
return Expression::Default();
}
@@ -1107,6 +1107,39 @@
return Expression::Default();
}
+void PreParser::CheckDuplicate(DuplicateFinder* finder,
+ i::Token::Value property,
+ int type,
+ bool* ok) {
+ int old_type;
+ if (property == i::Token::NUMBER) {
+ old_type = finder->AddNumber(scanner_->literal_ascii_string(), type);
+ } else if (scanner_->is_literal_ascii()) {
+ old_type = finder->AddAsciiSymbol(scanner_->literal_ascii_string(),
+ type);
+ } else {
+ old_type = finder->AddUC16Symbol(scanner_->literal_uc16_string(), type);
+ }
+ if (HasConflict(old_type, type)) {
+ if (IsDataDataConflict(old_type, type)) {
+ // Both are data properties.
+ if (!strict_mode()) return;
+ ReportMessageAt(scanner_->location(),
+ "strict_duplicate_property", NULL);
+ } else if (IsDataAccessorConflict(old_type, type)) {
+ // Both a data and an accessor property with the same name.
+ ReportMessageAt(scanner_->location(),
+ "accessor_data_property", NULL);
+ } else {
+ ASSERT(IsAccessorAccessorConflict(old_type, type));
+ // Both accessors of the same type.
+ ReportMessageAt(scanner_->location(),
+ "accessor_get_set", NULL);
+ }
+ *ok = false;
+ }
+}
+
PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
// ObjectLiteral ::
@@ -1116,6 +1149,7 @@
// )*[','] '}'
Expect(i::Token::LBRACE, CHECK_OK);
+ DuplicateFinder duplicate_finder(scanner_->unicode_cache());
while (peek() != i::Token::RBRACE) {
i::Token::Value next = peek();
switch (next) {
@@ -1140,24 +1174,30 @@
if (!is_keyword) {
LogSymbol();
}
+ PropertyType type = is_getter ? kGetterProperty : kSetterProperty;
+ CheckDuplicate(&duplicate_finder, name, type, CHECK_OK);
ParseFunctionLiteral(CHECK_OK);
if (peek() != i::Token::RBRACE) {
Expect(i::Token::COMMA, CHECK_OK);
}
continue; // restart the while
}
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
break;
}
case i::Token::STRING:
Consume(next);
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
GetStringSymbol();
break;
case i::Token::NUMBER:
Consume(next);
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
break;
default:
if (i::Token::IsKeyword(next)) {
Consume(next);
+ CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
} else {
// Unexpected token.
*ok = false;
@@ -1182,9 +1222,7 @@
bool* ok) {
if (!scanner_->ScanRegExpPattern(seen_equal)) {
Next();
- i::JavaScriptScanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "unterminated_regexp", NULL);
+ ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL);
*ok = false;
return Expression::Default();
}
@@ -1193,9 +1231,7 @@
if (!scanner_->ScanRegExpFlags()) {
Next();
- i::JavaScriptScanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "invalid_regexp_flags", NULL);
+ ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL);
*ok = false;
return Expression::Default();
}
@@ -1240,6 +1276,7 @@
Expect(i::Token::LPAREN, CHECK_OK);
int start_position = scanner_->location().beg_pos;
bool done = (peek() == i::Token::RPAREN);
+ DuplicateFinder duplicate_finder(scanner_->unicode_cache());
while (!done) {
Identifier id = ParseIdentifier(CHECK_OK);
if (!id.IsValidStrictVariable()) {
@@ -1248,6 +1285,20 @@
id,
CHECK_OK);
}
+ int prev_value;
+ if (scanner_->is_literal_ascii()) {
+ prev_value =
+ duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1);
+ } else {
+ prev_value =
+ duplicate_finder.AddUC16Symbol(scanner_->literal_uc16_string(), 1);
+ }
+
+ if (prev_value != 0) {
+ SetStrictModeViolation(scanner_->location(),
+ "strict_param_dupe",
+ CHECK_OK);
+ }
done = (peek() == i::Token::RPAREN);
if (!done) {
Expect(i::Token::COMMA, CHECK_OK);
@@ -1399,13 +1450,18 @@
const char* type,
bool* ok) {
if (strict_mode()) {
- ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ ReportMessageAt(location, type, NULL);
*ok = false;
return;
}
// Delay report in case this later turns out to be strict code
// (i.e., for function names and parameters prior to a "use strict"
// directive).
+ // It's safe to overwrite an existing violation.
+ // It's either from a function that turned out to be non-strict,
+ // or it's in the current function (and we just need to report
+ // one error), or it's in a unclosed nesting function that wasn't
+ // strict (otherwise we would already be in strict mode).
strict_mode_violation_location_ = location;
strict_mode_violation_type_ = type;
}
@@ -1417,11 +1473,9 @@
i::Scanner::Location location = strict_mode_violation_location_;
if (location.IsValid() &&
location.beg_pos > beg_pos && location.end_pos < end_pos) {
- ReportMessageAt(location.beg_pos, location.end_pos,
- strict_mode_violation_type_, NULL);
+ ReportMessageAt(location, strict_mode_violation_type_, NULL);
*ok = false;
}
- strict_mode_violation_location_ = i::Scanner::Location::invalid();
}
@@ -1436,7 +1490,7 @@
type = "strict_reserved_word";
}
if (strict_mode()) {
- ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
+ ReportMessageAt(location, type, NULL);
*ok = false;
return;
}
@@ -1488,4 +1542,138 @@
next == i::Token::FUTURE_RESERVED_WORD ||
next == i::Token::FUTURE_STRICT_RESERVED_WORD;
}
+
+
+int DuplicateFinder::AddAsciiSymbol(i::Vector<const char> key, int value) {
+ return AddSymbol(i::Vector<const byte>::cast(key), true, value);
+}
+
+int DuplicateFinder::AddUC16Symbol(i::Vector<const uint16_t> key, int value) {
+ return AddSymbol(i::Vector<const byte>::cast(key), false, value);
+}
+
+int DuplicateFinder::AddSymbol(i::Vector<const byte> key,
+ bool is_ascii,
+ int value) {
+ uint32_t hash = Hash(key, is_ascii);
+ byte* encoding = BackupKey(key, is_ascii);
+ i::HashMap::Entry* entry = map_.Lookup(encoding, hash, true);
+ int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+ entry->value =
+ reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
+ return old_value;
+}
+
+
+int DuplicateFinder::AddNumber(i::Vector<const char> key, int value) {
+ ASSERT(key.length() > 0);
+ // Quick check for already being in canonical form.
+ if (IsNumberCanonical(key)) {
+ return AddAsciiSymbol(key, value);
+ }
+
+ int flags = i::ALLOW_HEX | i::ALLOW_OCTALS;
+ double double_value = StringToDouble(unicode_constants_, key, flags, 0.0);
+ int length;
+ const char* string;
+ if (!isfinite(double_value)) {
+ string = "Infinity";
+ length = 8; // strlen("Infinity");
+ } else {
+ string = DoubleToCString(double_value,
+ i::Vector<char>(number_buffer_, kBufferSize));
+ length = i::StrLength(string);
+ }
+ return AddSymbol(i::Vector<const byte>(reinterpret_cast<const byte*>(string),
+ length), true, value);
+}
+
+
+bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) {
+ // Test for a safe approximation of number literals that are already
+ // in canonical form: max 15 digits, no leading zeroes, except an
+ // integer part that is a single zero, and no trailing zeros below
+ // the decimal point.
+ int pos = 0;
+ int length = number.length();
+ if (number.length() > 15) return false;
+ if (number[pos] == '0') {
+ pos++;
+ } else {
+ while (pos < length &&
+ static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++;
+ }
+ if (length == pos) return true;
+ if (number[pos] != '.') return false;
+ pos++;
+ bool invalid_last_digit = true;
+ while (pos < length) {
+ byte digit = number[pos] - '0';
+ if (digit > '9' - '0') return false;
+ invalid_last_digit = (digit == 0);
+ pos++;
+ }
+ return !invalid_last_digit;
+}
+
+
+uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) {
+ // Primitive hash function, almost identical to the one used
+ // for strings (except that it's seeded by the length and ASCII-ness).
+ int length = key.length();
+ uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ;
+ for (int i = 0; i < length; i++) {
+ uint32_t c = key[i];
+ hash = (hash + c) * 1025;
+ hash ^= (hash >> 6);
+ }
+ return hash;
+}
+
+
+bool DuplicateFinder::Match(void* first, void* second) {
+ // Decode lengths.
+ // Length + ASCII-bit is encoded as base 128, most significant heptet first,
+ // with a 8th bit being non-zero while there are more heptets.
+ // The value encodes the number of bytes following, and whether the original
+ // was ASCII.
+ byte* s1 = reinterpret_cast<byte*>(first);
+ byte* s2 = reinterpret_cast<byte*>(second);
+ uint32_t length_ascii_field = 0;
+ byte c1;
+ do {
+ c1 = *s1;
+ if (c1 != *s2) return false;
+ length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f);
+ s1++;
+ s2++;
+ } while ((c1 & 0x80) != 0);
+ int length = static_cast<int>(length_ascii_field >> 1);
+ return memcmp(s1, s2, length) == 0;
+}
+
+
+byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes,
+ bool is_ascii) {
+ uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0);
+ backing_store_.StartSequence();
+ // Emit ascii_length as base-128 encoded number, with the 7th bit set
+ // on the byte of every heptet except the last, least significant, one.
+ if (ascii_length >= (1 << 7)) {
+ if (ascii_length >= (1 << 14)) {
+ if (ascii_length >= (1 << 21)) {
+ if (ascii_length >= (1 << 28)) {
+ backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80));
+ }
+ backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u));
+ }
+ backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u));
+ }
+ backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u));
+ }
+ backing_store_.Add(static_cast<byte>(ascii_length & 0x7f));
+
+ backing_store_.AddBlock(bytes);
+ return backing_store_.EndSequence().start();
+}
} } // v8::preparser
diff --git a/src/preparser.h b/src/preparser.h
index cd0a530..b97b7cf 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -28,9 +28,19 @@
#ifndef V8_PREPARSER_H
#define V8_PREPARSER_H
+#include "token.h"
+#include "scanner.h"
+
namespace v8 {
+
+namespace internal {
+class UnicodeCache;
+}
+
namespace preparser {
+typedef uint8_t byte;
+
// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
// See preparse-data-format.h for the data format.
@@ -46,6 +56,53 @@
namespace i = v8::internal;
+class DuplicateFinder {
+ public:
+ explicit DuplicateFinder(i::UnicodeCache* constants)
+ : unicode_constants_(constants),
+ backing_store_(16),
+ map_(&Match) { }
+
+ int AddAsciiSymbol(i::Vector<const char> key, int value);
+ int AddUC16Symbol(i::Vector<const uint16_t> key, int value);
+ // Add a a number literal by converting it (if necessary)
+ // to the string that ToString(ToNumber(literal)) would generate.
+ // and then adding that string with AddAsciiSymbol.
+ // This string is the actual value used as key in an object literal,
+ // and the one that must be different from the other keys.
+ int AddNumber(i::Vector<const char> key, int value);
+
+ private:
+ int AddSymbol(i::Vector<const byte> key, bool is_ascii, int value);
+ // Backs up the key and its length in the backing store.
+ // The backup is stored with a base 127 encoding of the
+ // length (plus a bit saying whether the string is ASCII),
+ // followed by the bytes of the key.
+ byte* BackupKey(i::Vector<const byte> key, bool is_ascii);
+
+ // Compare two encoded keys (both pointing into the backing store)
+ // for having the same base-127 encoded lengths and ASCII-ness,
+ // and then having the same 'length' bytes following.
+ static bool Match(void* first, void* second);
+ // Creates a hash from a sequence of bytes.
+ static uint32_t Hash(i::Vector<const byte> key, bool is_ascii);
+ // Checks whether a string containing a JS number is its canonical
+ // form.
+ static bool IsNumberCanonical(i::Vector<const char> key);
+
+ // Size of buffer. Sufficient for using it to call DoubleToCString in
+ // from conversions.h.
+ static const int kBufferSize = 100;
+
+ i::UnicodeCache* unicode_constants_;
+ // Backing store used to store strings used as hashmap keys.
+ i::SequenceCollector<unsigned char> backing_store_;
+ i::HashMap map_;
+ // Buffer used for string->number->canonical string conversions.
+ char number_buffer_[kBufferSize];
+};
+
+
class PreParser {
public:
enum PreParseResult {
@@ -53,7 +110,7 @@
kPreParseSuccess
};
- ~PreParser() { }
+ ~PreParser() {}
// Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully
@@ -67,6 +124,45 @@
}
private:
+ // Used to detect duplicates in object literals. Each of the values
+ // kGetterProperty, kSetterProperty and kValueProperty represents
+ // a type of object literal property. When parsing a property, its
+ // type value is stored in the DuplicateFinder for the property name.
+ // Values are chosen so that having intersection bits means the there is
+ // an incompatibility.
+ // I.e., you can add a getter to a property that already has a setter, since
+ // kGetterProperty and kSetterProperty doesn't intersect, but not if it
+ // already has a getter or a value. Adding the getter to an existing
+ // setter will store the value (kGetterProperty | kSetterProperty), which
+ // is incompatible with adding any further properties.
+ enum PropertyType {
+ kNone = 0,
+ // Bit patterns representing different object literal property types.
+ kGetterProperty = 1,
+ kSetterProperty = 2,
+ kValueProperty = 7,
+ // Helper constants.
+ kValueFlag = 4
+ };
+
+ // Checks the type of conflict based on values coming from PropertyType.
+ bool HasConflict(int type1, int type2) { return (type1 & type2) != 0; }
+ bool IsDataDataConflict(int type1, int type2) {
+ return ((type1 & type2) & kValueFlag) != 0;
+ }
+ bool IsDataAccessorConflict(int type1, int type2) {
+ return ((type1 ^ type2) & kValueFlag) != 0;
+ }
+ bool IsAccessorAccessorConflict(int type1, int type2) {
+ return ((type1 | type2) & kValueFlag) == 0;
+ }
+
+
+ void CheckDuplicate(DuplicateFinder* finder,
+ i::Token::Value property,
+ int type,
+ bool* ok);
+
// These types form an algebra over syntactic categories that is just
// rich enough to let us recognize and propagate the constructs that
// are either being counted in the preparser data, or is important
@@ -371,6 +467,11 @@
// Report syntax error
void ReportUnexpectedToken(i::Token::Value token);
+ void ReportMessageAt(i::Scanner::Location location,
+ const char* type,
+ const char* name_opt) {
+ log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
+ }
void ReportMessageAt(int start_pos,
int end_pos,
const char* type,
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index b034293..663af28 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -131,11 +131,6 @@
}
-void PrettyPrinter::VisitExitContextStatement(ExitContextStatement* node) {
- Print("<exit context>");
-}
-
-
void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) {
PrintLabels(node->labels());
Print("switch (");
@@ -284,28 +279,6 @@
}
-void PrettyPrinter::VisitSlot(Slot* node) {
- switch (node->type()) {
- case Slot::PARAMETER:
- Print("parameter[%d]", node->index());
- break;
- case Slot::LOCAL:
- Print("local[%d]", node->index());
- break;
- case Slot::CONTEXT:
- Print("context[%d]", node->index());
- break;
- case Slot::LOOKUP:
- Print("lookup[");
- PrintLiteral(node->var()->name(), false);
- Print("]");
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
void PrettyPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteral(node->name(), false);
}
@@ -660,17 +633,14 @@
void AstPrinter::PrintLabelsIndented(const char* info, ZoneStringList* labels) {
if (labels != NULL && labels->length() > 0) {
- if (info == NULL) {
- PrintIndented("LABELS ");
- } else {
- PrintIndented(info);
- Print(" ");
- }
+ PrintIndented(info == NULL ? "LABELS" : info);
+ Print(" ");
PrintLabels(labels);
+ Print("\n");
} else if (info != NULL) {
PrintIndented(info);
+ Print("\n");
}
- Print("\n");
}
@@ -751,7 +721,7 @@
if (node->fun() == NULL) {
// var or const declarations
PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
- node->proxy()->AsVariable(),
+ node->proxy()->var(),
node->proxy()->name());
} else {
// function declarations
@@ -805,11 +775,6 @@
}
-void AstPrinter::VisitExitContextStatement(ExitContextStatement* node) {
- PrintIndented("EXIT CONTEXT\n");
-}
-
-
void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
IndentedScope indent(this, "SWITCH");
PrintLabelsIndented(NULL, node->labels());
@@ -959,20 +924,27 @@
}
-void AstPrinter::VisitSlot(Slot* node) {
- PrintIndented("SLOT ");
- PrettyPrinter::VisitSlot(node);
- Print("\n");
-}
-
-
void AstPrinter::VisitVariableProxy(VariableProxy* node) {
- PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name());
Variable* var = node->var();
- if (var != NULL && var->rewrite() != NULL) {
- IndentedScope indent(this);
- Visit(var->rewrite());
+ EmbeddedVector<char, 128> buf;
+ int pos = OS::SNPrintF(buf, "VAR PROXY");
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ break;
+ case Variable::PARAMETER:
+ OS::SNPrintF(buf + pos, " parameter[%d]", var->index());
+ break;
+ case Variable::LOCAL:
+ OS::SNPrintF(buf + pos, " local[%d]", var->index());
+ break;
+ case Variable::CONTEXT:
+ OS::SNPrintF(buf + pos, " context[%d]", var->index());
+ break;
+ case Variable::LOOKUP:
+ OS::SNPrintF(buf + pos, " lookup");
+ break;
}
+ PrintLiteralWithModeIndented(buf.start(), var, node->name());
}
@@ -1130,7 +1102,7 @@
void JsonAstBuilder::AddAttribute(const char* name, Handle<String> value) {
- SmartPointer<char> value_string = value->ToCString();
+ SmartArrayPointer<char> value_string = value->ToCString();
AddAttributePrefix(name);
Print("\"%s\"", *value_string);
}
@@ -1202,11 +1174,6 @@
}
-void JsonAstBuilder::VisitExitContextStatement(ExitContextStatement* stmt) {
- TagScope tag(this, "ExitContextStatement");
-}
-
-
void JsonAstBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
TagScope tag(this, "SwitchStatement");
}
@@ -1287,39 +1254,32 @@
}
-void JsonAstBuilder::VisitSlot(Slot* expr) {
- TagScope tag(this, "Slot");
+void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
+ TagScope tag(this, "Variable");
{
AttributesScope attributes(this);
- switch (expr->type()) {
- case Slot::PARAMETER:
- AddAttribute("type", "PARAMETER");
+ Variable* var = expr->var();
+ AddAttribute("name", var->name());
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ AddAttribute("location", "UNALLOCATED");
break;
- case Slot::LOCAL:
- AddAttribute("type", "LOCAL");
+ case Variable::PARAMETER:
+ AddAttribute("location", "PARAMETER");
+ AddAttribute("index", var->index());
break;
- case Slot::CONTEXT:
- AddAttribute("type", "CONTEXT");
+ case Variable::LOCAL:
+ AddAttribute("location", "LOCAL");
+ AddAttribute("index", var->index());
break;
- case Slot::LOOKUP:
- AddAttribute("type", "LOOKUP");
+ case Variable::CONTEXT:
+ AddAttribute("location", "CONTEXT");
+ AddAttribute("index", var->index());
+ break;
+ case Variable::LOOKUP:
+ AddAttribute("location", "LOOKUP");
break;
}
- AddAttribute("index", expr->index());
- }
-}
-
-
-void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
- if (expr->var()->rewrite() == NULL) {
- TagScope tag(this, "VariableProxy");
- {
- AttributesScope attributes(this);
- AddAttribute("name", expr->name());
- AddAttribute("mode", Variable::Mode2String(expr->var()->mode()));
- }
- } else {
- Visit(expr->var()->rewrite());
}
}
diff --git a/src/prettyprinter.h b/src/prettyprinter.h
index 080081d..a26c48e 100644
--- a/src/prettyprinter.h
+++ b/src/prettyprinter.h
@@ -52,7 +52,6 @@
// Print a node to stdout.
static void PrintOut(AstNode* node);
- virtual void VisitSlot(Slot* node);
// Individual nodes
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
@@ -87,7 +86,6 @@
const char* PrintProgram(FunctionLiteral* program);
// Individual nodes
- virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
@@ -163,7 +161,6 @@
void AddAttribute(const char* name, bool value);
// AST node visit functions.
- virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 8f4bc6c..88d6e87 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -78,22 +78,6 @@
}
-void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
- CodeTree::Locator locator;
- tree_.Insert(addr, &locator);
- locator.set_value(CodeEntryInfo(entry, size));
-}
-
-
-void CodeMap::MoveCode(Address from, Address to) {
- tree_.Move(from, to);
-}
-
-void CodeMap::DeleteCode(Address addr) {
- tree_.Remove(addr);
-}
-
-
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) {
case GC:
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 5a95445..adf55ad 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -492,6 +492,28 @@
CodeMap::CodeEntryInfo(NULL, 0);
+void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
+ DeleteAllCoveredCode(addr, addr + size);
+ CodeTree::Locator locator;
+ tree_.Insert(addr, &locator);
+ locator.set_value(CodeEntryInfo(entry, size));
+}
+
+
+void CodeMap::DeleteAllCoveredCode(Address start, Address end) {
+ List<Address> to_delete;
+ Address addr = end - 1;
+ while (addr >= start) {
+ CodeTree::Locator locator;
+ if (!tree_.FindGreatestLessThan(addr, &locator)) break;
+ Address start2 = locator.key(), end2 = start2 + locator.value().size;
+ if (start2 < end && start < end2) to_delete.Add(start2);
+ addr = start2 - 1;
+ }
+ for (int i = 0; i < to_delete.length(); ++i) tree_.Remove(to_delete[i]);
+}
+
+
CodeEntry* CodeMap::FindEntry(Address addr) {
CodeTree::Locator locator;
if (tree_.FindGreatestLessThan(addr, &locator)) {
@@ -520,6 +542,16 @@
}
+void CodeMap::MoveCode(Address from, Address to) {
+ if (from == to) return;
+ CodeTree::Locator locator;
+ if (!tree_.Find(from, &locator)) return;
+ CodeEntryInfo entry = locator.value();
+ tree_.Remove(from);
+ AddCode(to, entry.entry, entry.size);
+}
+
+
void CodeMap::CodeTreePrinter::Call(
const Address& key, const CodeMap::CodeEntryInfo& value) {
OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
diff --git a/src/profile-generator.h b/src/profile-generator.h
index fbb6fab..da1fdc3 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -238,9 +238,8 @@
class CodeMap {
public:
CodeMap() : next_shared_id_(1) { }
- INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
- INLINE(void MoveCode(Address from, Address to));
- INLINE(void DeleteCode(Address addr));
+ void AddCode(Address addr, CodeEntry* entry, unsigned size);
+ void MoveCode(Address from, Address to);
CodeEntry* FindEntry(Address addr);
int GetSharedId(Address addr);
@@ -270,6 +269,8 @@
void Call(const Address& key, const CodeEntryInfo& value);
};
+ void DeleteAllCoveredCode(Address start, Address end);
+
// Fake CodeEntry pointer to distinguish shared function entries.
static CodeEntry* const kSharedFunctionCodeEntry;
diff --git a/src/property.cc b/src/property.cc
index dd23209..7cc2df5 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -52,8 +52,8 @@
GetTransitionMap()->Print(out);
PrintF(out, "\n");
break;
- case EXTERNAL_ARRAY_TRANSITION:
- PrintF(out, " -type = external array transition\n");
+ case ELEMENTS_TRANSITION:
+ PrintF(out, " -type = elements transition\n");
PrintF(out, " -map:\n");
GetTransitionMap()->Print(out);
PrintF(out, "\n");
diff --git a/src/property.h b/src/property.h
index ddecc92..e7d9fc5 100644
--- a/src/property.h
+++ b/src/property.h
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -112,14 +112,14 @@
: Descriptor(key, map, attributes, MAP_TRANSITION) { }
};
-class ExternalArrayTransitionDescriptor: public Descriptor {
+class ElementsTransitionDescriptor: public Descriptor {
public:
- ExternalArrayTransitionDescriptor(String* key,
- Map* map,
- ExternalArrayType array_type)
+ ElementsTransitionDescriptor(String* key,
+ Map* map,
+ ElementsKind elements_kind)
: Descriptor(key, map, PropertyDetails(NONE,
- EXTERNAL_ARRAY_TRANSITION,
- array_type)) { }
+ ELEMENTS_TRANSITION,
+ elements_kind)) { }
};
// Marks a field name in a map so that adding the field is guaranteed
@@ -281,7 +281,7 @@
Map* GetTransitionMap() {
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION ||
- type() == EXTERNAL_ARRAY_TRANSITION);
+ type() == ELEMENTS_TRANSITION);
return Map::cast(GetValue());
}
diff --git a/src/proxy.js b/src/proxy.js
index 2839159..4e44cd4 100644
--- a/src/proxy.js
+++ b/src/proxy.js
@@ -29,36 +29,6 @@
var $Proxy = global.Proxy
-var fundamentalTraps = [
- "getOwnPropertyDescriptor",
- "getPropertyDescriptor",
- "getOwnPropertyNames",
- "getPropertyNames",
- "defineProperty",
- "delete",
- "fix",
-]
-
-var derivedTraps = [
- "has",
- "hasOwn",
- "get",
- "set",
- "enumerate",
- "keys",
-]
-
-var functionTraps = [
- "callTrap",
- "constructTrap",
-]
-
-$Proxy.createFunction = function(handler, callTrap, constructTrap) {
- handler.callTrap = callTrap
- handler.constructTrap = constructTrap
- $Proxy.create(handler)
-}
-
$Proxy.create = function(handler, proto) {
if (!IS_SPEC_OBJECT(handler))
throw MakeTypeError("handler_non_object", ["create"])
@@ -66,6 +36,20 @@
return %CreateJSProxy(handler, proto)
}
+$Proxy.createFunction = function(handler, callTrap, constructTrap) {
+ if (!IS_SPEC_OBJECT(handler))
+ throw MakeTypeError("handler_non_object", ["create"])
+ if (!IS_SPEC_FUNCTION(callTrap))
+ throw MakeTypeError("trap_function_expected", ["createFunction", "call"])
+ if (IS_UNDEFINED(constructTrap)) {
+ constructTrap = callTrap
+ } else if (!IS_SPEC_FUNCTION(constructTrap)) {
+ throw MakeTypeError("trap_function_expected",
+ ["createFunction", "construct"])
+ }
+ return %CreateJSFunctionProxy(
+ handler, callTrap, constructTrap, $Function.prototype)
+}
@@ -73,6 +57,13 @@
// Builtins
////////////////////////////////////////////////////////////////////////////////
+function DelegateCallAndConstruct(callTrap, constructTrap) {
+ return function() {
+ return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
+ this, arguments, 0, %_ArgumentsLength())
+ }
+}
+
function DerivedGetTrap(receiver, name) {
var desc = this.getPropertyDescriptor(name)
if (IS_UNDEFINED(desc)) { return desc }
diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h
index 75cf8bf..262ead2 100644
--- a/src/regexp-macro-assembler-irregexp.h
+++ b/src/regexp-macro-assembler-irregexp.h
@@ -107,6 +107,7 @@
virtual IrregexpImplementation Implementation();
virtual Handle<HeapObject> GetCode(Handle<String> source);
+
private:
void Expand();
// Code and bitmap emission.
diff --git a/src/regexp-macro-assembler-tracer.h b/src/regexp-macro-assembler-tracer.h
index 8c6cf3a..1cf0349 100644
--- a/src/regexp-macro-assembler-tracer.h
+++ b/src/regexp-macro-assembler-tracer.h
@@ -95,6 +95,7 @@
virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
virtual void ClearRegisters(int reg_from, int reg_to);
virtual void WriteStackPointerToRegister(int reg);
+
private:
RegExpMacroAssembler* assembler_;
};
diff --git a/src/regexp-stack.h b/src/regexp-stack.h
index 5943206..5684239 100644
--- a/src/regexp-stack.h
+++ b/src/regexp-stack.h
@@ -89,6 +89,7 @@
char* ArchiveStack(char* to);
char* RestoreStack(char* from);
void FreeThreadResources() { thread_local_.Free(); }
+
private:
RegExpStack();
~RegExpStack();
diff --git a/src/regexp.js b/src/regexp.js
index a7f42d5..38d4496 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -405,7 +405,8 @@
// -------------------------------------------------------------------
-function SetupRegExp() {
+function SetUpRegExp() {
+ %CheckIsBootstrapping();
%FunctionSetInstanceClassName($RegExp, 'RegExp');
%FunctionSetPrototype($RegExp, new $Object());
%SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
@@ -484,5 +485,4 @@
}
}
-
-SetupRegExp();
+SetUpRegExp();
diff --git a/src/rewriter.cc b/src/rewriter.cc
index ad6ce05..3d4c2dc 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -208,7 +208,6 @@
void Processor::VisitDeclaration(Declaration* node) {}
void Processor::VisitEmptyStatement(EmptyStatement* node) {}
void Processor::VisitReturnStatement(ReturnStatement* node) {}
-void Processor::VisitExitContextStatement(ExitContextStatement* node) {}
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {}
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 917f6d0..26d8846 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -115,10 +115,8 @@
}
SharedFunctionInfo* shared = function->shared();
- // If the code is not optimizable or references context slots, don't try OSR.
- if (!shared->code()->optimizable() || !shared->allows_lazy_compilation()) {
- return;
- }
+ // If the code is not optimizable, don't try OSR.
+ if (!shared->code()->optimizable()) return;
// We are not prepared to do OSR for a function that already has an
// allocated arguments object. The optimized code would bypass it for
diff --git a/src/runtime.cc b/src/runtime.cc
index 50f9ce1..813f98f 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -32,6 +32,7 @@
#include "accessors.h"
#include "api.h"
#include "arguments.h"
+#include "bootstrapper.h"
#include "codegen.h"
#include "compilation-cache.h"
#include "compiler.h"
@@ -51,7 +52,7 @@
#include "runtime-profiler.h"
#include "runtime.h"
#include "scopeinfo.h"
-#include "smart-pointer.h"
+#include "smart-array-pointer.h"
#include "string-search.h"
#include "stub-cache.h"
#include "v8threads.h"
@@ -176,7 +177,7 @@
// Pixel elements cannot be created using an object literal.
ASSERT(!copy->HasExternalArrayElements());
switch (copy->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
FixedArray* elements = FixedArray::cast(copy->elements());
if (elements->map() == heap->fixed_cow_array_map()) {
isolate->counters()->cow_arrays_created_runtime()->Increment();
@@ -200,7 +201,7 @@
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
NumberDictionary* element_dictionary = copy->element_dictionary();
int capacity = element_dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
@@ -219,19 +220,19 @@
}
break;
}
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
// No contained objects, nothing to do.
break;
}
@@ -612,6 +613,19 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
+ ASSERT(args.length() == 4);
+ Object* handler = args[0];
+ Object* call_trap = args[1];
+ Object* construct_trap = args[2];
+ Object* prototype = args[3];
+ Object* used_prototype =
+ prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
+ return isolate->heap()->AllocateJSFunctionProxy(
+ handler, call_trap, construct_trap, used_prototype);
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
ASSERT(args.length() == 1);
Object* obj = args[0];
@@ -619,6 +633,13 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
+ ASSERT(args.length() == 1);
+ Object* obj = args[0];
+ return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSProxy, proxy, args[0]);
@@ -626,6 +647,20 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
+ return proxy->call_trap();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
+ return proxy->construct_trap();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSProxy, proxy, args[0]);
@@ -1149,22 +1184,14 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
- ASSERT(args.length() == 4);
+ ASSERT(args.length() == 3);
HandleScope scope(isolate);
Handle<GlobalObject> global = Handle<GlobalObject>(
isolate->context()->global());
Handle<Context> context = args.at<Context>(0);
CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
- bool is_eval = args.smi_at(2) == 1;
- StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
- ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
-
- // Compute the property attributes. According to ECMA-262, section
- // 13, page 71, the property must be read-only and
- // non-deletable. However, neither SpiderMonkey nor KJS creates the
- // property as read-only, so we don't either.
- PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
+ CONVERT_SMI_ARG_CHECKED(flags, 2);
// Traverse the name/value pairs and set the properties.
int length = pairs->length();
@@ -1177,7 +1204,7 @@
// assign to it when evaluating the assignment for "const x =
// <expr>" the initial value is the hole.
bool is_const_property = value->IsTheHole();
-
+ bool is_function_declaration = false;
if (value->IsUndefined() || is_const_property) {
// Lookup the property in the global object, and don't set the
// value of the variable if the property is already there.
@@ -1226,6 +1253,7 @@
}
}
} else {
+ is_function_declaration = true;
// Copy the function and update its context. Use it as value.
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(value);
@@ -1239,10 +1267,6 @@
LookupResult lookup;
global->LocalLookup(*name, &lookup);
- PropertyAttributes attributes = is_const_property
- ? static_cast<PropertyAttributes>(base | READ_ONLY)
- : base;
-
// There's a local property that we need to overwrite because
// we're either declaring a function or there's an interceptor
// that claims the property is absent.
@@ -1257,6 +1281,19 @@
return ThrowRedeclarationError(isolate, type, name);
}
+ // Compute the property attributes. According to ECMA-262, section
+ // 13, page 71, the property must be read-only and
+ // non-deletable. However, neither SpiderMonkey nor KJS creates the
+ // property as read-only, so we don't either.
+ int attr = NONE;
+ if ((flags & kDeclareGlobalsEvalFlag) == 0) {
+ attr |= DONT_DELETE;
+ }
+ bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
+ if (is_const_property || (is_native && is_function_declaration)) {
+ attr |= READ_ONLY;
+ }
+
// Safari does not allow the invocation of callback setters for
// function declarations. To mimic this behavior, we do not allow
// the invocation of setters for function values. This makes a
@@ -1267,20 +1304,24 @@
if (value->IsJSFunction()) {
// Do not change DONT_DELETE to false from true.
if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
- attributes = static_cast<PropertyAttributes>(
- attributes | (lookup.GetAttributes() & DONT_DELETE));
+ attr |= lookup.GetAttributes() & DONT_DELETE;
}
+ PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
+
RETURN_IF_EMPTY_HANDLE(isolate,
SetLocalPropertyIgnoreAttributes(global,
name,
value,
attributes));
} else {
+ StrictModeFlag strict_mode =
+ ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
+ : kNonStrictMode;
RETURN_IF_EMPTY_HANDLE(isolate,
SetProperty(global,
name,
value,
- attributes,
+ static_cast<PropertyAttributes>(attr),
strict_mode));
}
}
@@ -2202,6 +2243,11 @@
// are guaranteed to be in old space.
target->set_literals(*literals, SKIP_WRITE_BARRIER);
target->set_next_function_link(isolate->heap()->undefined_value());
+
+ if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
+ isolate->logger()->LogExistingFunction(
+ shared, Handle<Code>(shared->code()));
+ }
}
target->set_context(*context);
@@ -2499,7 +2545,7 @@
class CompiledReplacement {
public:
CompiledReplacement()
- : parts_(1), replacement_substrings_(0) {}
+ : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
void Compile(Handle<String> replacement,
int capture_count,
@@ -2515,6 +2561,10 @@
return parts_.length();
}
+ bool simple_hint() {
+ return simple_hint_;
+ }
+
private:
enum PartType {
SUBJECT_PREFIX = 1,
@@ -2573,7 +2623,7 @@
};
template<typename Char>
- static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
+ static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
Vector<Char> characters,
int capture_count,
int subject_length) {
@@ -2670,14 +2720,17 @@
if (length > last) {
if (last == 0) {
parts->Add(ReplacementPart::ReplacementString());
+ return true;
} else {
parts->Add(ReplacementPart::ReplacementSubString(last, length));
}
}
+ return false;
}
ZoneList<ReplacementPart> parts_;
ZoneList<Handle<String> > replacement_substrings_;
+ bool simple_hint_;
};
@@ -2689,16 +2742,16 @@
String::FlatContent content = replacement->GetFlatContent();
ASSERT(content.IsFlat());
if (content.IsAscii()) {
- ParseReplacementPattern(&parts_,
- content.ToAsciiVector(),
- capture_count,
- subject_length);
+ simple_hint_ = ParseReplacementPattern(&parts_,
+ content.ToAsciiVector(),
+ capture_count,
+ subject_length);
} else {
ASSERT(content.IsTwoByte());
- ParseReplacementPattern(&parts_,
- content.ToUC16Vector(),
- capture_count,
- subject_length);
+ simple_hint_ = ParseReplacementPattern(&parts_,
+ content.ToUC16Vector(),
+ capture_count,
+ subject_length);
}
}
Isolate* isolate = replacement->GetIsolate();
@@ -2761,6 +2814,170 @@
}
+void FindAsciiStringIndices(Vector<const char> subject,
+ char pattern,
+ ZoneList<int>* indices,
+ unsigned int limit) {
+ ASSERT(limit > 0);
+ // Collect indices of pattern in subject using memchr.
+ // Stop after finding at most limit values.
+ const char* subject_start = reinterpret_cast<const char*>(subject.start());
+ const char* subject_end = subject_start + subject.length();
+ const char* pos = subject_start;
+ while (limit > 0) {
+ pos = reinterpret_cast<const char*>(
+ memchr(pos, pattern, subject_end - pos));
+ if (pos == NULL) return;
+ indices->Add(static_cast<int>(pos - subject_start));
+ pos++;
+ limit--;
+ }
+}
+
+
+template <typename SubjectChar, typename PatternChar>
+void FindStringIndices(Isolate* isolate,
+ Vector<const SubjectChar> subject,
+ Vector<const PatternChar> pattern,
+ ZoneList<int>* indices,
+ unsigned int limit) {
+ ASSERT(limit > 0);
+ // Collect indices of pattern in subject.
+ // Stop after finding at most limit values.
+ int pattern_length = pattern.length();
+ int index = 0;
+ StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
+ while (limit > 0) {
+ index = search.Search(subject, index);
+ if (index < 0) return;
+ indices->Add(index);
+ index += pattern_length;
+ limit--;
+ }
+}
+
+
+void FindStringIndicesDispatch(Isolate* isolate,
+ String* subject,
+ String* pattern,
+ ZoneList<int>* indices,
+ unsigned int limit) {
+ {
+ AssertNoAllocation no_gc;
+ String::FlatContent subject_content = subject->GetFlatContent();
+ String::FlatContent pattern_content = pattern->GetFlatContent();
+ ASSERT(subject_content.IsFlat());
+ ASSERT(pattern_content.IsFlat());
+ if (subject_content.IsAscii()) {
+ Vector<const char> subject_vector = subject_content.ToAsciiVector();
+ if (pattern_content.IsAscii()) {
+ Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
+ if (pattern_vector.length() == 1) {
+ FindAsciiStringIndices(subject_vector,
+ pattern_vector[0],
+ indices,
+ limit);
+ } else {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_vector,
+ indices,
+ limit);
+ }
+ } else {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_content.ToUC16Vector(),
+ indices,
+ limit);
+ }
+ } else {
+ Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
+ if (pattern->IsAsciiRepresentation()) {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_content.ToAsciiVector(),
+ indices,
+ limit);
+ } else {
+ FindStringIndices(isolate,
+ subject_vector,
+ pattern_content.ToUC16Vector(),
+ indices,
+ limit);
+ }
+ }
+ }
+}
+
+
+template<typename ResultSeqString>
+MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
+ Isolate* isolate,
+ Handle<String> subject,
+ Handle<JSRegExp> pattern_regexp,
+ Handle<String> replacement) {
+ ASSERT(subject->IsFlat());
+ ASSERT(replacement->IsFlat());
+
+ ZoneScope zone_space(isolate, DELETE_ON_EXIT);
+ ZoneList<int> indices(8);
+ ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
+ String* pattern =
+ String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
+ int subject_len = subject->length();
+ int pattern_len = pattern->length();
+ int replacement_len = replacement->length();
+
+ FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
+
+ int matches = indices.length();
+ if (matches == 0) return *subject;
+
+ int result_len = (replacement_len - pattern_len) * matches + subject_len;
+ int subject_pos = 0;
+ int result_pos = 0;
+
+ Handle<ResultSeqString> result;
+ if (ResultSeqString::kHasAsciiEncoding) {
+ result = Handle<ResultSeqString>::cast(
+ isolate->factory()->NewRawAsciiString(result_len));
+ } else {
+ result = Handle<ResultSeqString>::cast(
+ isolate->factory()->NewRawTwoByteString(result_len));
+ }
+
+ for (int i = 0; i < matches; i++) {
+ // Copy non-matched subject content.
+ if (subject_pos < indices.at(i)) {
+ String::WriteToFlat(*subject,
+ result->GetChars() + result_pos,
+ subject_pos,
+ indices.at(i));
+ result_pos += indices.at(i) - subject_pos;
+ }
+
+ // Replace match.
+ if (replacement_len > 0) {
+ String::WriteToFlat(*replacement,
+ result->GetChars() + result_pos,
+ 0,
+ replacement_len);
+ result_pos += replacement_len;
+ }
+
+ subject_pos = indices.at(i) + pattern_len;
+ }
+ // Add remaining subject content at the end.
+ if (subject_pos < subject_len) {
+ String::WriteToFlat(*subject,
+ result->GetChars() + result_pos,
+ subject_pos,
+ subject_len);
+ }
+ return *result;
+}
+
MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
Isolate* isolate,
@@ -2800,6 +3017,20 @@
bool is_global = regexp_handle->GetFlags().is_global();
+ // Shortcut for simple non-regexp global replacements
+ if (is_global &&
+ regexp->TypeTag() == JSRegExp::ATOM &&
+ compiled_replacement.simple_hint()) {
+ if (subject_handle->HasOnlyAsciiChars() &&
+ replacement_handle->HasOnlyAsciiChars()) {
+ return StringReplaceStringWithString<SeqAsciiString>(
+ isolate, subject_handle, regexp_handle, replacement_handle);
+ } else {
+ return StringReplaceStringWithString<SeqTwoByteString>(
+ isolate, subject_handle, regexp_handle, replacement_handle);
+ }
+ }
+
// Guessing the number of parts that the final result string is built
// from. Global regexps can match any number of times, so we guess
// conservatively.
@@ -2885,6 +3116,20 @@
Handle<String> subject_handle(subject);
Handle<JSRegExp> regexp_handle(regexp);
+
+ // Shortcut for simple non-regexp global replacements
+ if (regexp_handle->GetFlags().is_global() &&
+ regexp_handle->TypeTag() == JSRegExp::ATOM) {
+ Handle<String> empty_string_handle(HEAP->empty_string());
+ if (subject_handle->HasOnlyAsciiChars()) {
+ return StringReplaceStringWithString<SeqAsciiString>(
+ isolate, subject_handle, regexp_handle, empty_string_handle);
+ } else {
+ return StringReplaceStringWithString<SeqTwoByteString>(
+ isolate, subject_handle, regexp_handle, empty_string_handle);
+ }
+ }
+
Handle<JSArray> last_match_info_handle(last_match_info);
Handle<Object> match = RegExpImpl::Exec(regexp_handle,
subject_handle,
@@ -4104,8 +4349,7 @@
Handle<NumberDictionary> extended_dictionary =
NumberDictionarySet(dictionary, index, obj_value, details);
if (*extended_dictionary != *dictionary) {
- if (js_object->GetElementsKind() ==
- JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
+ if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
} else {
js_object->set_elements(*extended_dictionary);
@@ -4895,6 +5139,7 @@
ASSERT(heap_obj->IsUndefined());
return isolate->heap()->undefined_symbol();
case JS_FUNCTION_TYPE:
+ case JS_FUNCTION_PROXY_TYPE:
return isolate->heap()->function_symbol();
default:
// For any kind of object not handled above, the spec rule for
@@ -5933,49 +6178,6 @@
}
-void FindAsciiStringIndices(Vector<const char> subject,
- char pattern,
- ZoneList<int>* indices,
- unsigned int limit) {
- ASSERT(limit > 0);
- // Collect indices of pattern in subject using memchr.
- // Stop after finding at most limit values.
- const char* subject_start = reinterpret_cast<const char*>(subject.start());
- const char* subject_end = subject_start + subject.length();
- const char* pos = subject_start;
- while (limit > 0) {
- pos = reinterpret_cast<const char*>(
- memchr(pos, pattern, subject_end - pos));
- if (pos == NULL) return;
- indices->Add(static_cast<int>(pos - subject_start));
- pos++;
- limit--;
- }
-}
-
-
-template <typename SubjectChar, typename PatternChar>
-void FindStringIndices(Isolate* isolate,
- Vector<const SubjectChar> subject,
- Vector<const PatternChar> pattern,
- ZoneList<int>* indices,
- unsigned int limit) {
- ASSERT(limit > 0);
- // Collect indices of pattern in subject.
- // Stop after finding at most limit values.
- int pattern_length = pattern.length();
- int index = 0;
- StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
- while (limit > 0) {
- index = search.Search(subject, index);
- if (index < 0) return;
- indices->Add(index);
- index += pattern_length;
- limit--;
- }
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
ASSERT(args.length() == 3);
HandleScope handle_scope(isolate);
@@ -5987,6 +6189,19 @@
int pattern_length = pattern->length();
RUNTIME_ASSERT(pattern_length > 0);
+ if (limit == 0xffffffffu) {
+ Handle<Object> cached_answer(StringSplitCache::Lookup(
+ isolate->heap()->string_split_cache(),
+ *subject,
+ *pattern));
+ if (*cached_answer != Smi::FromInt(0)) {
+ Handle<JSArray> result =
+ isolate->factory()->NewJSArrayWithElements(
+ Handle<FixedArray>::cast(cached_answer));
+ return *result;
+ }
+ }
+
// The limit can be very large (0xffffffffu), but since the pattern
// isn't empty, we can never create more parts than ~half the length
// of the subject.
@@ -6002,53 +6217,7 @@
ZoneList<int> indices(initial_capacity);
if (!pattern->IsFlat()) FlattenString(pattern);
- // No allocation block.
- {
- AssertNoAllocation no_gc;
- String::FlatContent subject_content = subject->GetFlatContent();
- String::FlatContent pattern_content = pattern->GetFlatContent();
- ASSERT(subject_content.IsFlat());
- ASSERT(pattern_content.IsFlat());
- if (subject_content.IsAscii()) {
- Vector<const char> subject_vector = subject_content.ToAsciiVector();
- if (pattern_content.IsAscii()) {
- Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
- if (pattern_vector.length() == 1) {
- FindAsciiStringIndices(subject_vector,
- pattern_vector[0],
- &indices,
- limit);
- } else {
- FindStringIndices(isolate,
- subject_vector,
- pattern_vector,
- &indices,
- limit);
- }
- } else {
- FindStringIndices(isolate,
- subject_vector,
- pattern_content.ToUC16Vector(),
- &indices,
- limit);
- }
- } else {
- Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
- if (pattern->IsAsciiRepresentation()) {
- FindStringIndices(isolate,
- subject_vector,
- pattern_content.ToAsciiVector(),
- &indices,
- limit);
- } else {
- FindStringIndices(isolate,
- subject_vector,
- pattern_content.ToUC16Vector(),
- &indices,
- limit);
- }
- }
- }
+ FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
if (static_cast<uint32_t>(indices.length()) < limit) {
indices.Add(subject_length);
@@ -6080,6 +6249,16 @@
part_start = part_end + pattern_length;
}
+ if (limit == 0xffffffffu) {
+ if (result->HasFastElements()) {
+ StringSplitCache::Enter(isolate->heap(),
+ isolate->heap()->string_split_cache(),
+ *subject,
+ *pattern,
+ *elements);
+ }
+ }
+
return *result;
}
@@ -6662,7 +6841,12 @@
// Find total length of join result.
int string_length = 0;
bool is_ascii = separator->IsAsciiRepresentation();
- int max_string_length = SeqAsciiString::kMaxLength;
+ int max_string_length;
+ if (is_ascii) {
+ max_string_length = SeqAsciiString::kMaxLength;
+ } else {
+ max_string_length = SeqTwoByteString::kMaxLength;
+ }
bool overflow = false;
CONVERT_NUMBER_CHECKED(int, elements_length,
Int32, elements_array->length());
@@ -7640,7 +7824,7 @@
Handle<Map> old_map(result->map());
Handle<Map> new_map =
isolate->factory()->CopyMapDropTransitions(old_map);
- new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+ new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
result->set_map(*new_map);
result->set_elements(*parameter_map);
@@ -7768,8 +7952,8 @@
}
-static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
- int* total_argc) {
+static SmartArrayPointer<Object**> GetNonBoundArguments(int bound_argc,
+ int* total_argc) {
// Find frame containing arguments passed to the caller.
JavaScriptFrameIterator it;
JavaScriptFrame* frame = it.frame();
@@ -7785,7 +7969,7 @@
&args_slots);
*total_argc = bound_argc + args_count;
- SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
+ SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = args_slots[i].GetValue();
param_data[bound_argc + i] = val.location();
@@ -7797,7 +7981,7 @@
int args_count = frame->ComputeParametersCount();
*total_argc = bound_argc + args_count;
- SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
+ SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
for (int i = 0; i < args_count; i++) {
Handle<Object> val = Handle<Object>(frame->GetParameter(i));
param_data[bound_argc + i] = val.location();
@@ -7824,7 +8008,7 @@
}
int total_argc = 0;
- SmartPointer<Object**> param_data =
+ SmartArrayPointer<Object**> param_data =
GetNonBoundArguments(bound_argc, &total_argc);
for (int i = 0; i < bound_argc; i++) {
Handle<Object> val = Handle<Object>(bound_args->get(i));
@@ -7965,15 +8149,9 @@
}
#endif
- // Compile the target function. Here we compile using CompileLazyInLoop in
- // order to get the optimized version. This helps code like delta-blue
- // that calls performance-critical routines through constructors. A
- // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
- // direct call. Since the in-loop tracking takes place through CallICs
- // this means that things called through constructors are never known to
- // be in loops. We compile them as if they are in loops here just in case.
+ // Compile the target function.
ASSERT(!function->is_compiled());
- if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
+ if (!CompileLazy(function, KEEP_EXCEPTION)) {
return Failure::Exception();
}
@@ -7987,6 +8165,15 @@
HandleScope scope(isolate);
ASSERT(args.length() == 1);
Handle<JSFunction> function = args.at<JSFunction>(0);
+
+ // If the function is not compiled ignore the lazy
+ // recompilation. This can happen if the debugger is activated and
+ // the function is returned to the not compiled state.
+ if (!function->shared()->is_compiled()) {
+ function->ReplaceCode(function->shared()->code());
+ return function->code();
+ }
+
// If the function is not optimizable or debugger is active continue using the
// code from the full compiler.
if (!function->shared()->code()->optimizable() ||
@@ -8052,8 +8239,6 @@
if (type == Deoptimizer::EAGER) {
RUNTIME_ASSERT(function->IsOptimized());
- } else {
- RUNTIME_ASSERT(!function->IsOptimized());
}
// Avoid doing too much work when running with --always-opt and keep
@@ -8072,8 +8257,6 @@
it.Advance();
}
- // TODO(kasperl): For now, we cannot support removing the optimized
- // code when we have recursive invocations of the same function.
if (activations == 0) {
if (FLAG_trace_deopt) {
PrintF("[removing optimized code for: ");
@@ -8081,6 +8264,8 @@
PrintF("]\n");
}
function->ReplaceCode(function->shared()->code());
+ } else {
+ Deoptimizer::DeoptimizeFunction(*function);
}
return isolate->heap()->undefined_value();
}
@@ -8261,6 +8446,55 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
+ RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
+ return isolate->heap()->undefined_value();
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 5);
+ CONVERT_CHECKED(JSReceiver, fun, args[0]);
+ Object* receiver = args[1];
+ CONVERT_CHECKED(JSObject, arguments, args[2]);
+ CONVERT_CHECKED(Smi, shift, args[3]);
+ CONVERT_CHECKED(Smi, arity, args[4]);
+
+ int offset = shift->value();
+ int argc = arity->value();
+ ASSERT(offset >= 0);
+ ASSERT(argc >= 0);
+
+ // If there are too many arguments, allocate argv via malloc.
+ const int argv_small_size = 10;
+ Handle<Object> argv_small_buffer[argv_small_size];
+ SmartArrayPointer<Handle<Object> > argv_large_buffer;
+ Handle<Object>* argv = argv_small_buffer;
+ if (argc > argv_small_size) {
+ argv = new Handle<Object>[argc];
+ if (argv == NULL) return isolate->StackOverflow();
+ argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
+ }
+
+ for (int i = 0; i < argc; ++i) {
+ MaybeObject* maybe = arguments->GetElement(offset + i);
+ Object* object;
+ if (!maybe->To<Object>(&object)) return maybe;
+ argv[i] = Handle<Object>(object);
+ }
+
+ bool threw = false;
+ Handle<JSReceiver> hfun(fun);
+ Handle<Object> hreceiver(receiver);
+ Handle<Object> result = Execution::Call(
+ hfun, hreceiver, argc, reinterpret_cast<Object***>(argv), &threw, true);
+
+ if (threw) return Failure::Exception();
+ return *result;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -8737,7 +8971,7 @@
static void PrintString(String* str) {
// not uncommon to have empty strings
if (str->length() > 0) {
- SmartPointer<char> s =
+ SmartArrayPointer<char> s =
str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
PrintF("%s", *s);
}
@@ -9332,7 +9566,7 @@
uint32_t length = static_cast<uint32_t>(array->length()->Number());
int element_count = 0;
switch (array->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
// Fast elements can't have lengths that are not representable by
// a 32-bit signed integer.
ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
@@ -9343,7 +9577,7 @@
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dictionary(
NumberDictionary::cast(array->elements()));
int capacity = dictionary->Capacity();
@@ -9419,9 +9653,9 @@
static void CollectElementIndices(Handle<JSObject> object,
uint32_t range,
List<uint32_t>* indices) {
- JSObject::ElementsKind kind = object->GetElementsKind();
+ ElementsKind kind = object->GetElementsKind();
switch (kind) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(object->elements()));
uint32_t length = static_cast<uint32_t>(elements->length());
if (range < length) length = range;
@@ -9432,7 +9666,7 @@
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
uint32_t capacity = dict->Capacity();
for (uint32_t j = 0; j < capacity; j++) {
@@ -9451,47 +9685,47 @@
default: {
int dense_elements_length;
switch (kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
dense_elements_length =
ExternalPixelArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_BYTE_ELEMENTS: {
+ case EXTERNAL_BYTE_ELEMENTS: {
dense_elements_length =
ExternalByteArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
dense_elements_length =
ExternalUnsignedByteArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_SHORT_ELEMENTS: {
+ case EXTERNAL_SHORT_ELEMENTS: {
dense_elements_length =
ExternalShortArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
dense_elements_length =
ExternalUnsignedShortArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_INT_ELEMENTS: {
+ case EXTERNAL_INT_ELEMENTS: {
dense_elements_length =
ExternalIntArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
dense_elements_length =
ExternalUnsignedIntArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS: {
dense_elements_length =
ExternalFloatArray::cast(object->elements())->length();
break;
}
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
+ case EXTERNAL_DOUBLE_ELEMENTS: {
dense_elements_length =
ExternalDoubleArray::cast(object->elements())->length();
break;
@@ -9540,7 +9774,7 @@
ArrayConcatVisitor* visitor) {
uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
switch (receiver->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS: {
+ case FAST_ELEMENTS: {
// Run through the elements FixedArray and use HasElement and GetElement
// to check the prototype for missing elements.
Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
@@ -9561,7 +9795,7 @@
}
break;
}
- case JSObject::DICTIONARY_ELEMENTS: {
+ case DICTIONARY_ELEMENTS: {
Handle<NumberDictionary> dict(receiver->element_dictionary());
List<uint32_t> indices(dict->Capacity() / 2);
// Collect all indices in the object and the prototypes less
@@ -9583,7 +9817,7 @@
}
break;
}
- case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
+ case EXTERNAL_PIXEL_ELEMENTS: {
Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
receiver->elements()));
for (uint32_t j = 0; j < length; j++) {
@@ -9592,42 +9826,42 @@
}
break;
}
- case JSObject::EXTERNAL_BYTE_ELEMENTS: {
+ case EXTERNAL_BYTE_ELEMENTS: {
IterateExternalArrayElements<ExternalByteArray, int8_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_SHORT_ELEMENTS: {
+ case EXTERNAL_SHORT_ELEMENTS: {
IterateExternalArrayElements<ExternalShortArray, int16_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
isolate, receiver, true, true, visitor);
break;
}
- case JSObject::EXTERNAL_INT_ELEMENTS: {
+ case EXTERNAL_INT_ELEMENTS: {
IterateExternalArrayElements<ExternalIntArray, int32_t>(
isolate, receiver, true, false, visitor);
break;
}
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
isolate, receiver, true, false, visitor);
break;
}
- case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
+ case EXTERNAL_FLOAT_ELEMENTS: {
IterateExternalArrayElements<ExternalFloatArray, float>(
isolate, receiver, false, false, visitor);
break;
}
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
+ case EXTERNAL_DOUBLE_ELEMENTS: {
IterateExternalArrayElements<ExternalDoubleArray, double>(
isolate, receiver, false, false, visitor);
break;
@@ -9999,7 +10233,7 @@
}
case INTERCEPTOR:
case MAP_TRANSITION:
- case EXTERNAL_ARRAY_TRANSITION:
+ case ELEMENTS_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return heap->undefined_value();
@@ -10805,15 +11039,16 @@
at_local_(false) {
// Check whether the first scope is actually a local scope.
- if (context_->IsGlobalContext()) {
- // If there is a stack slot for .result then this local scope has been
- // created for evaluating top level code and it is not a real local scope.
- // Checking for the existence of .result seems fragile, but the scope info
- // saved with the code object does not otherwise have that information.
- int index = function_->shared()->scope_info()->
- StackSlotIndex(isolate_->heap()->result_symbol());
- at_local_ = index < 0;
- } else if (context_->IsFunctionContext()) {
+ // If there is a stack slot for .result then this local scope has been
+ // created for evaluating top level code and it is not a real local scope.
+ // Checking for the existence of .result seems fragile, but the scope info
+ // saved with the code object does not otherwise have that information.
+ int index = function_->shared()->scope_info()->
+ StackSlotIndex(isolate_->heap()->result_symbol());
+ if (index >= 0) {
+ local_done_ = true;
+ } else if (context_->IsGlobalContext() ||
+ context_->IsFunctionContext()) {
at_local_ = true;
} else if (context_->closure() != *function_) {
// The context_ is a block or with or catch block from the outer function.
@@ -10860,7 +11095,7 @@
}
// Return the type of the current scope.
- int Type() {
+ ScopeType Type() {
if (at_local_) {
return ScopeTypeLocal;
}
@@ -12289,7 +12524,7 @@
// Sets a v8 flag.
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
CONVERT_CHECKED(String, arg, args[0]);
- SmartPointer<char> flags =
+ SmartArrayPointer<char> flags =
arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
FlagList::SetFlagsFromString(*flags, StrLength(*flags));
return isolate->heap()->undefined_value();
diff --git a/src/runtime.h b/src/runtime.h
index 91a19df..1538b7d 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -79,6 +79,8 @@
F(PreventExtensions, 1, 1)\
\
/* Utilities */ \
+ F(CheckIsBootstrapping, 0, 1) \
+ F(Apply, 5, 1) \
F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \
F(NewArgumentsFast, 3, 1) \
@@ -286,8 +288,12 @@
\
/* Harmony proxies */ \
F(CreateJSProxy, 2, 1) \
+ F(CreateJSFunctionProxy, 4, 1) \
F(IsJSProxy, 1, 1) \
+ F(IsJSFunctionProxy, 1, 1) \
F(GetHandler, 1, 1) \
+ F(GetCallTrap, 1, 1) \
+ F(GetConstructTrap, 1, 1) \
F(Fix, 1, 1) \
\
/* Harmony weakmaps */ \
@@ -317,7 +323,7 @@
F(StoreContextSlot, 4, 1) \
\
/* Declarations and initialization */ \
- F(DeclareGlobals, 4, 1) \
+ F(DeclareGlobals, 3, 1) \
F(DeclareContextSlot, 4, 1) \
F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \
F(InitializeConstGlobal, 2, 1) \
@@ -663,6 +669,16 @@
static void PerformGC(Object* result);
};
+
+//---------------------------------------------------------------------------
+// Constants used by interface to runtime functions.
+
+enum kDeclareGlobalsFlags {
+ kDeclareGlobalsEvalFlag = 1 << 0,
+ kDeclareGlobalsStrictModeFlag = 1 << 1,
+ kDeclareGlobalsNativeFlag = 1 << 2
+};
+
} } // namespace v8::internal
#endif // V8_RUNTIME_H_
diff --git a/src/runtime.js b/src/runtime.js
index 4b600df..14ff1b6 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -48,6 +48,7 @@
const $Function = global.Function;
const $Boolean = global.Boolean;
const $NaN = 0/0;
+const builtins = this;
// ECMA-262 Section 11.9.3.
function EQUALS(y) {
@@ -365,7 +366,7 @@
// an expensive ToBoolean conversion in the generated code.
function INSTANCE_OF(F) {
var V = this;
- if (!IS_FUNCTION(F)) {
+ if (!IS_SPEC_FUNCTION(F)) {
throw %MakeTypeError('instanceof_function_expected', [V]);
}
@@ -407,7 +408,7 @@
if (!IS_FUNCTION(delegate)) {
throw %MakeTypeError('called_non_callable', [typeof this]);
}
- return delegate.apply(this, arguments);
+ return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
}
@@ -416,7 +417,32 @@
if (!IS_FUNCTION(delegate)) {
throw %MakeTypeError('called_non_callable', [typeof this]);
}
- return delegate.apply(this, arguments);
+ return %Apply(delegate, this, arguments, 0, %_ArgumentsLength());
+}
+
+
+function CALL_FUNCTION_PROXY() {
+ var arity = %_ArgumentsLength() - 1;
+ var proxy = %_Arguments(arity); // The proxy comes in as an additional arg.
+ var trap = %GetCallTrap(proxy);
+ return %Apply(trap, this, arguments, 0, arity);
+}
+
+
+function CALL_FUNCTION_PROXY_AS_CONSTRUCTOR(proxy) {
+ var arity = %_ArgumentsLength() - 1;
+ var trap = %GetConstructTrap(proxy);
+ var receiver = void 0;
+ if (!IS_UNDEFINED(trap)) {
+ trap = %GetCallTrap(proxy);
+ var proto = proxy.prototype;
+ if (!IS_SPEC_OBJECT(proto) && proto !== null) {
+ throw MakeTypeError("proto_object_or_null", [proto]);
+ }
+ receiver = new global.Object();
+ receiver.__proto__ = proto;
+ }
+ return %Apply(trap, this, arguments, 1, arity);
}
@@ -427,7 +453,8 @@
// that takes care of more eventualities.
if (IS_ARRAY(args)) {
length = args.length;
- if (%_IsSmi(length) && length >= 0 && length < 0x800000 && IS_FUNCTION(this)) {
+ if (%_IsSmi(length) && length >= 0 && length < 0x800000 &&
+ IS_SPEC_FUNCTION(this)) {
return length;
}
}
@@ -441,7 +468,7 @@
throw %MakeRangeError('stack_overflow', []);
}
- if (!IS_FUNCTION(this)) {
+ if (!IS_SPEC_FUNCTION(this)) {
throw %MakeTypeError('apply_non_function', [ %ToString(this), typeof this ]);
}
@@ -609,13 +636,13 @@
// ECMA-262, section 8.6.2.6, page 28.
function DefaultNumber(x) {
var valueOf = x.valueOf;
- if (IS_FUNCTION(valueOf)) {
+ if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
if (%IsPrimitive(v)) return v;
}
var toString = x.toString;
- if (IS_FUNCTION(toString)) {
+ if (IS_SPEC_FUNCTION(toString)) {
var s = %_CallFunction(x, toString);
if (%IsPrimitive(s)) return s;
}
@@ -627,13 +654,13 @@
// ECMA-262, section 8.6.2.6, page 28.
function DefaultString(x) {
var toString = x.toString;
- if (IS_FUNCTION(toString)) {
+ if (IS_SPEC_FUNCTION(toString)) {
var s = %_CallFunction(x, toString);
if (%IsPrimitive(s)) return s;
}
var valueOf = x.valueOf;
- if (IS_FUNCTION(valueOf)) {
+ if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
if (%IsPrimitive(v)) return v;
}
diff --git a/src/safepoint-table.cc b/src/safepoint-table.cc
index 28cf6e6..bcd0a1d 100644
--- a/src/safepoint-table.cc
+++ b/src/safepoint-table.cc
@@ -68,8 +68,8 @@
entries_ = pc_and_deoptimization_indexes_ +
(length_ * kPcAndDeoptimizationIndexSize);
ASSERT(entry_size_ > 0);
- ASSERT_EQ(SafepointEntry::DeoptimizationIndexField::max(),
- Safepoint::kNoDeoptimizationIndex);
+ STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
+ Safepoint::kNoDeoptimizationIndex);
}
diff --git a/src/scanner-base.cc b/src/scanner-base.cc
deleted file mode 100644
index 62eee1a..0000000
--- a/src/scanner-base.cc
+++ /dev/null
@@ -1,1090 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Features shared by parsing and pre-parsing scanners.
-
-#include "../include/v8stdint.h"
-#include "scanner-base.h"
-#include "char-predicates-inl.h"
-
-namespace v8 {
-namespace internal {
-
-// ----------------------------------------------------------------------------
-// Scanner
-
-Scanner::Scanner(UnicodeCache* unicode_cache)
- : unicode_cache_(unicode_cache) { }
-
-
-uc32 Scanner::ScanHexNumber(int expected_length) {
- ASSERT(expected_length <= 4); // prevent overflow
-
- uc32 digits[4] = { 0, 0, 0, 0 };
- uc32 x = 0;
- for (int i = 0; i < expected_length; i++) {
- digits[i] = c0_;
- int d = HexValue(c0_);
- if (d < 0) {
- // According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
- // should be illegal, but other JS VMs just return the
- // non-escaped version of the original character.
-
- // Push back digits that we have advanced past.
- for (int j = i-1; j >= 0; j--) {
- PushBack(digits[j]);
- }
- return -1;
- }
- x = x * 16 + d;
- Advance();
- }
-
- return x;
-}
-
-
-
-// ----------------------------------------------------------------------------
-// JavaScriptScanner
-
-JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants)
- : Scanner(scanner_contants),
- octal_pos_(Location::invalid()),
- harmony_block_scoping_(false) { }
-
-
-void JavaScriptScanner::Initialize(UC16CharacterStream* source) {
- source_ = source;
- // Need to capture identifiers in order to recognize "get" and "set"
- // in object literals.
- Init();
- // Skip initial whitespace allowing HTML comment ends just like
- // after a newline and scan first token.
- has_line_terminator_before_next_ = true;
- SkipWhiteSpace();
- Scan();
-}
-
-
-// Ensure that tokens can be stored in a byte.
-STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
-
-// Table of one-character tokens, by character (0x00..0x7f only).
-static const byte one_char_tokens[] = {
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LPAREN, // 0x28
- Token::RPAREN, // 0x29
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::COMMA, // 0x2c
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::COLON, // 0x3a
- Token::SEMICOLON, // 0x3b
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::CONDITIONAL, // 0x3f
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LBRACK, // 0x5b
- Token::ILLEGAL,
- Token::RBRACK, // 0x5d
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::ILLEGAL,
- Token::LBRACE, // 0x7b
- Token::ILLEGAL,
- Token::RBRACE, // 0x7d
- Token::BIT_NOT, // 0x7e
- Token::ILLEGAL
-};
-
-
-Token::Value JavaScriptScanner::Next() {
- current_ = next_;
- has_line_terminator_before_next_ = false;
- has_multiline_comment_before_next_ = false;
- if (static_cast<unsigned>(c0_) <= 0x7f) {
- Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]);
- if (token != Token::ILLEGAL) {
- int pos = source_pos();
- next_.token = token;
- next_.location.beg_pos = pos;
- next_.location.end_pos = pos + 1;
- Advance();
- return current_.token;
- }
- }
- Scan();
- return current_.token;
-}
-
-
-static inline bool IsByteOrderMark(uc32 c) {
- // The Unicode value U+FFFE is guaranteed never to be assigned as a
- // Unicode character; this implies that in a Unicode context the
- // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
- // character expressed in little-endian byte order (since it could
- // not be a U+FFFE character expressed in big-endian byte
- // order). Nevertheless, we check for it to be compatible with
- // Spidermonkey.
- return c == 0xFEFF || c == 0xFFFE;
-}
-
-
-bool JavaScriptScanner::SkipWhiteSpace() {
- int start_position = source_pos();
-
- while (true) {
- // We treat byte-order marks (BOMs) as whitespace for better
- // compatibility with Spidermonkey and other JavaScript engines.
- while (unicode_cache_->IsWhiteSpace(c0_) || IsByteOrderMark(c0_)) {
- // IsWhiteSpace() includes line terminators!
- if (unicode_cache_->IsLineTerminator(c0_)) {
- // Ignore line terminators, but remember them. This is necessary
- // for automatic semicolon insertion.
- has_line_terminator_before_next_ = true;
- }
- Advance();
- }
-
- // If there is an HTML comment end '-->' at the beginning of a
- // line (with only whitespace in front of it), we treat the rest
- // of the line as a comment. This is in line with the way
- // SpiderMonkey handles it.
- if (c0_ == '-' && has_line_terminator_before_next_) {
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '>') {
- // Treat the rest of the line as a comment.
- SkipSingleLineComment();
- // Continue skipping white space after the comment.
- continue;
- }
- PushBack('-'); // undo Advance()
- }
- PushBack('-'); // undo Advance()
- }
- // Return whether or not we skipped any characters.
- return source_pos() != start_position;
- }
-}
-
-
-Token::Value JavaScriptScanner::SkipSingleLineComment() {
- Advance();
-
- // The line terminator at the end of the line is not considered
- // to be part of the single-line comment; it is recognized
- // separately by the lexical grammar and becomes part of the
- // stream of input elements for the syntactic grammar (see
- // ECMA-262, section 7.4).
- while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
- Advance();
- }
-
- return Token::WHITESPACE;
-}
-
-
-Token::Value JavaScriptScanner::SkipMultiLineComment() {
- ASSERT(c0_ == '*');
- Advance();
-
- while (c0_ >= 0) {
- uc32 ch = c0_;
- Advance();
- if (unicode_cache_->IsLineTerminator(ch)) {
- // Following ECMA-262, section 7.4, a comment containing
- // a newline will make the comment count as a line-terminator.
- has_multiline_comment_before_next_ = true;
- }
- // If we have reached the end of the multi-line comment, we
- // consume the '/' and insert a whitespace. This way all
- // multi-line comments are treated as whitespace.
- if (ch == '*' && c0_ == '/') {
- c0_ = ' ';
- return Token::WHITESPACE;
- }
- }
-
- // Unterminated multi-line comment.
- return Token::ILLEGAL;
-}
-
-
-Token::Value JavaScriptScanner::ScanHtmlComment() {
- // Check for <!-- comments.
- ASSERT(c0_ == '!');
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '-') return SkipSingleLineComment();
- PushBack('-'); // undo Advance()
- }
- PushBack('!'); // undo Advance()
- ASSERT(c0_ == '!');
- return Token::LT;
-}
-
-
-void JavaScriptScanner::Scan() {
- next_.literal_chars = NULL;
- Token::Value token;
- do {
- // Remember the position of the next token
- next_.location.beg_pos = source_pos();
-
- switch (c0_) {
- case ' ':
- case '\t':
- Advance();
- token = Token::WHITESPACE;
- break;
-
- case '\n':
- Advance();
- has_line_terminator_before_next_ = true;
- token = Token::WHITESPACE;
- break;
-
- case '"': case '\'':
- token = ScanString();
- break;
-
- case '<':
- // < <= << <<= <!--
- Advance();
- if (c0_ == '=') {
- token = Select(Token::LTE);
- } else if (c0_ == '<') {
- token = Select('=', Token::ASSIGN_SHL, Token::SHL);
- } else if (c0_ == '!') {
- token = ScanHtmlComment();
- } else {
- token = Token::LT;
- }
- break;
-
- case '>':
- // > >= >> >>= >>> >>>=
- Advance();
- if (c0_ == '=') {
- token = Select(Token::GTE);
- } else if (c0_ == '>') {
- // >> >>= >>> >>>=
- Advance();
- if (c0_ == '=') {
- token = Select(Token::ASSIGN_SAR);
- } else if (c0_ == '>') {
- token = Select('=', Token::ASSIGN_SHR, Token::SHR);
- } else {
- token = Token::SAR;
- }
- } else {
- token = Token::GT;
- }
- break;
-
- case '=':
- // = == ===
- Advance();
- if (c0_ == '=') {
- token = Select('=', Token::EQ_STRICT, Token::EQ);
- } else {
- token = Token::ASSIGN;
- }
- break;
-
- case '!':
- // ! != !==
- Advance();
- if (c0_ == '=') {
- token = Select('=', Token::NE_STRICT, Token::NE);
- } else {
- token = Token::NOT;
- }
- break;
-
- case '+':
- // + ++ +=
- Advance();
- if (c0_ == '+') {
- token = Select(Token::INC);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_ADD);
- } else {
- token = Token::ADD;
- }
- break;
-
- case '-':
- // - -- --> -=
- Advance();
- if (c0_ == '-') {
- Advance();
- if (c0_ == '>' && has_line_terminator_before_next_) {
- // For compatibility with SpiderMonkey, we skip lines that
- // start with an HTML comment end '-->'.
- token = SkipSingleLineComment();
- } else {
- token = Token::DEC;
- }
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_SUB);
- } else {
- token = Token::SUB;
- }
- break;
-
- case '*':
- // * *=
- token = Select('=', Token::ASSIGN_MUL, Token::MUL);
- break;
-
- case '%':
- // % %=
- token = Select('=', Token::ASSIGN_MOD, Token::MOD);
- break;
-
- case '/':
- // / // /* /=
- Advance();
- if (c0_ == '/') {
- token = SkipSingleLineComment();
- } else if (c0_ == '*') {
- token = SkipMultiLineComment();
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_DIV);
- } else {
- token = Token::DIV;
- }
- break;
-
- case '&':
- // & && &=
- Advance();
- if (c0_ == '&') {
- token = Select(Token::AND);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_BIT_AND);
- } else {
- token = Token::BIT_AND;
- }
- break;
-
- case '|':
- // | || |=
- Advance();
- if (c0_ == '|') {
- token = Select(Token::OR);
- } else if (c0_ == '=') {
- token = Select(Token::ASSIGN_BIT_OR);
- } else {
- token = Token::BIT_OR;
- }
- break;
-
- case '^':
- // ^ ^=
- token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
- break;
-
- case '.':
- // . Number
- Advance();
- if (IsDecimalDigit(c0_)) {
- token = ScanNumber(true);
- } else {
- token = Token::PERIOD;
- }
- break;
-
- case ':':
- token = Select(Token::COLON);
- break;
-
- case ';':
- token = Select(Token::SEMICOLON);
- break;
-
- case ',':
- token = Select(Token::COMMA);
- break;
-
- case '(':
- token = Select(Token::LPAREN);
- break;
-
- case ')':
- token = Select(Token::RPAREN);
- break;
-
- case '[':
- token = Select(Token::LBRACK);
- break;
-
- case ']':
- token = Select(Token::RBRACK);
- break;
-
- case '{':
- token = Select(Token::LBRACE);
- break;
-
- case '}':
- token = Select(Token::RBRACE);
- break;
-
- case '?':
- token = Select(Token::CONDITIONAL);
- break;
-
- case '~':
- token = Select(Token::BIT_NOT);
- break;
-
- default:
- if (unicode_cache_->IsIdentifierStart(c0_)) {
- token = ScanIdentifierOrKeyword();
- } else if (IsDecimalDigit(c0_)) {
- token = ScanNumber(false);
- } else if (SkipWhiteSpace()) {
- token = Token::WHITESPACE;
- } else if (c0_ < 0) {
- token = Token::EOS;
- } else {
- token = Select(Token::ILLEGAL);
- }
- break;
- }
-
- // Continue scanning for tokens as long as we're just skipping
- // whitespace.
- } while (token == Token::WHITESPACE);
-
- next_.location.end_pos = source_pos();
- next_.token = token;
-}
-
-
-void JavaScriptScanner::SeekForward(int pos) {
- // After this call, we will have the token at the given position as
- // the "next" token. The "current" token will be invalid.
- if (pos == next_.location.beg_pos) return;
- int current_pos = source_pos();
- ASSERT_EQ(next_.location.end_pos, current_pos);
- // Positions inside the lookahead token aren't supported.
- ASSERT(pos >= current_pos);
- if (pos != current_pos) {
- source_->SeekForward(pos - source_->pos());
- Advance();
- // This function is only called to seek to the location
- // of the end of a function (at the "}" token). It doesn't matter
- // whether there was a line terminator in the part we skip.
- has_line_terminator_before_next_ = false;
- has_multiline_comment_before_next_ = false;
- }
- Scan();
-}
-
-
-void JavaScriptScanner::ScanEscape() {
- uc32 c = c0_;
- Advance();
-
- // Skip escaped newlines.
- if (unicode_cache_->IsLineTerminator(c)) {
- // Allow CR+LF newlines in multiline string literals.
- if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
- // Allow LF+CR newlines in multiline string literals.
- if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
- return;
- }
-
- switch (c) {
- case '\'': // fall through
- case '"' : // fall through
- case '\\': break;
- case 'b' : c = '\b'; break;
- case 'f' : c = '\f'; break;
- case 'n' : c = '\n'; break;
- case 'r' : c = '\r'; break;
- case 't' : c = '\t'; break;
- case 'u' : {
- c = ScanHexNumber(4);
- if (c < 0) c = 'u';
- break;
- }
- case 'v' : c = '\v'; break;
- case 'x' : {
- c = ScanHexNumber(2);
- if (c < 0) c = 'x';
- break;
- }
- case '0' : // fall through
- case '1' : // fall through
- case '2' : // fall through
- case '3' : // fall through
- case '4' : // fall through
- case '5' : // fall through
- case '6' : // fall through
- case '7' : c = ScanOctalEscape(c, 2); break;
- }
-
- // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
- // should be illegal, but they are commonly handled
- // as non-escaped characters by JS VMs.
- AddLiteralChar(c);
-}
-
-
-// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
-// ECMA-262. Other JS VMs support them.
-uc32 JavaScriptScanner::ScanOctalEscape(uc32 c, int length) {
- uc32 x = c - '0';
- int i = 0;
- for (; i < length; i++) {
- int d = c0_ - '0';
- if (d < 0 || d > 7) break;
- int nx = x * 8 + d;
- if (nx >= 256) break;
- x = nx;
- Advance();
- }
- // Anything except '\0' is an octal escape sequence, illegal in strict mode.
- // Remember the position of octal escape sequences so that an error
- // can be reported later (in strict mode).
- // We don't report the error immediately, because the octal escape can
- // occur before the "use strict" directive.
- if (c != '0' || i > 0) {
- octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
- }
- return x;
-}
-
-
-Token::Value JavaScriptScanner::ScanString() {
- uc32 quote = c0_;
- Advance(); // consume quote
-
- LiteralScope literal(this);
- while (c0_ != quote && c0_ >= 0
- && !unicode_cache_->IsLineTerminator(c0_)) {
- uc32 c = c0_;
- Advance();
- if (c == '\\') {
- if (c0_ < 0) return Token::ILLEGAL;
- ScanEscape();
- } else {
- AddLiteralChar(c);
- }
- }
- if (c0_ != quote) return Token::ILLEGAL;
- literal.Complete();
-
- Advance(); // consume quote
- return Token::STRING;
-}
-
-
-void JavaScriptScanner::ScanDecimalDigits() {
- while (IsDecimalDigit(c0_))
- AddLiteralCharAdvance();
-}
-
-
-Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
- ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
-
- enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
-
- LiteralScope literal(this);
- if (seen_period) {
- // we have already seen a decimal point of the float
- AddLiteralChar('.');
- ScanDecimalDigits(); // we know we have at least one digit
-
- } else {
- // if the first character is '0' we must check for octals and hex
- if (c0_ == '0') {
- int start_pos = source_pos(); // For reporting octal positions.
- AddLiteralCharAdvance();
-
- // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
- if (c0_ == 'x' || c0_ == 'X') {
- // hex number
- kind = HEX;
- AddLiteralCharAdvance();
- if (!IsHexDigit(c0_)) {
- // we must have at least one hex digit after 'x'/'X'
- return Token::ILLEGAL;
- }
- while (IsHexDigit(c0_)) {
- AddLiteralCharAdvance();
- }
- } else if ('0' <= c0_ && c0_ <= '7') {
- // (possible) octal number
- kind = OCTAL;
- while (true) {
- if (c0_ == '8' || c0_ == '9') {
- kind = DECIMAL;
- break;
- }
- if (c0_ < '0' || '7' < c0_) {
- // Octal literal finished.
- octal_pos_ = Location(start_pos, source_pos());
- break;
- }
- AddLiteralCharAdvance();
- }
- }
- }
-
- // Parse decimal digits and allow trailing fractional part.
- if (kind == DECIMAL) {
- ScanDecimalDigits(); // optional
- if (c0_ == '.') {
- AddLiteralCharAdvance();
- ScanDecimalDigits(); // optional
- }
- }
- }
-
- // scan exponent, if any
- if (c0_ == 'e' || c0_ == 'E') {
- ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
- if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed
- // scan exponent
- AddLiteralCharAdvance();
- if (c0_ == '+' || c0_ == '-')
- AddLiteralCharAdvance();
- if (!IsDecimalDigit(c0_)) {
- // we must have at least one decimal digit after 'e'/'E'
- return Token::ILLEGAL;
- }
- ScanDecimalDigits();
- }
-
- // The source character immediately following a numeric literal must
- // not be an identifier start or a decimal digit; see ECMA-262
- // section 7.8.3, page 17 (note that we read only one decimal digit
- // if the value is 0).
- if (IsDecimalDigit(c0_) || unicode_cache_->IsIdentifierStart(c0_))
- return Token::ILLEGAL;
-
- literal.Complete();
-
- return Token::NUMBER;
-}
-
-
-uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
- Advance();
- if (c0_ != 'u') return -1;
- Advance();
- uc32 result = ScanHexNumber(4);
- if (result < 0) PushBack('u');
- return result;
-}
-
-
-// ----------------------------------------------------------------------------
-// Keyword Matcher
-
-#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
- KEYWORD_GROUP('b') \
- KEYWORD("break", Token::BREAK) \
- KEYWORD_GROUP('c') \
- KEYWORD("case", Token::CASE) \
- KEYWORD("catch", Token::CATCH) \
- KEYWORD("class", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("const", Token::CONST) \
- KEYWORD("continue", Token::CONTINUE) \
- KEYWORD_GROUP('d') \
- KEYWORD("debugger", Token::DEBUGGER) \
- KEYWORD("default", Token::DEFAULT) \
- KEYWORD("delete", Token::DELETE) \
- KEYWORD("do", Token::DO) \
- KEYWORD_GROUP('e') \
- KEYWORD("else", Token::ELSE) \
- KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("export", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \
- KEYWORD_GROUP('f') \
- KEYWORD("false", Token::FALSE_LITERAL) \
- KEYWORD("finally", Token::FINALLY) \
- KEYWORD("for", Token::FOR) \
- KEYWORD("function", Token::FUNCTION) \
- KEYWORD_GROUP('i') \
- KEYWORD("if", Token::IF) \
- KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("import", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("in", Token::IN) \
- KEYWORD("instanceof", Token::INSTANCEOF) \
- KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('l') \
- KEYWORD("let", harmony_block_scoping \
- ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('n') \
- KEYWORD("new", Token::NEW) \
- KEYWORD("null", Token::NULL_LITERAL) \
- KEYWORD_GROUP('p') \
- KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD_GROUP('r') \
- KEYWORD("return", Token::RETURN) \
- KEYWORD_GROUP('s') \
- KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \
- KEYWORD("super", Token::FUTURE_RESERVED_WORD) \
- KEYWORD("switch", Token::SWITCH) \
- KEYWORD_GROUP('t') \
- KEYWORD("this", Token::THIS) \
- KEYWORD("throw", Token::THROW) \
- KEYWORD("true", Token::TRUE_LITERAL) \
- KEYWORD("try", Token::TRY) \
- KEYWORD("typeof", Token::TYPEOF) \
- KEYWORD_GROUP('v') \
- KEYWORD("var", Token::VAR) \
- KEYWORD("void", Token::VOID) \
- KEYWORD_GROUP('w') \
- KEYWORD("while", Token::WHILE) \
- KEYWORD("with", Token::WITH) \
- KEYWORD_GROUP('y') \
- KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD)
-
-
-static Token::Value KeywordOrIdentifierToken(const char* input,
- int input_length,
- bool harmony_block_scoping) {
- ASSERT(input_length >= 1);
- const int kMinLength = 2;
- const int kMaxLength = 10;
- if (input_length < kMinLength || input_length > kMaxLength) {
- return Token::IDENTIFIER;
- }
- switch (input[0]) {
- default:
-#define KEYWORD_GROUP_CASE(ch) \
- break; \
- case ch:
-#define KEYWORD(keyword, token) \
- { \
- /* 'keyword' is a char array, so sizeof(keyword) is */ \
- /* strlen(keyword) plus 1 for the NUL char. */ \
- const int keyword_length = sizeof(keyword) - 1; \
- STATIC_ASSERT(keyword_length >= kMinLength); \
- STATIC_ASSERT(keyword_length <= kMaxLength); \
- if (input_length == keyword_length && \
- input[1] == keyword[1] && \
- (keyword_length <= 2 || input[2] == keyword[2]) && \
- (keyword_length <= 3 || input[3] == keyword[3]) && \
- (keyword_length <= 4 || input[4] == keyword[4]) && \
- (keyword_length <= 5 || input[5] == keyword[5]) && \
- (keyword_length <= 6 || input[6] == keyword[6]) && \
- (keyword_length <= 7 || input[7] == keyword[7]) && \
- (keyword_length <= 8 || input[8] == keyword[8]) && \
- (keyword_length <= 9 || input[9] == keyword[9])) { \
- return token; \
- } \
- }
- KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
- }
- return Token::IDENTIFIER;
-}
-
-
-Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
- ASSERT(unicode_cache_->IsIdentifierStart(c0_));
- LiteralScope literal(this);
- // Scan identifier start character.
- if (c0_ == '\\') {
- uc32 c = ScanIdentifierUnicodeEscape();
- // Only allow legal identifier start characters.
- if (c < 0 ||
- c == '\\' || // No recursive escapes.
- !unicode_cache_->IsIdentifierStart(c)) {
- return Token::ILLEGAL;
- }
- AddLiteralChar(c);
- return ScanIdentifierSuffix(&literal);
- }
-
- uc32 first_char = c0_;
- Advance();
- AddLiteralChar(first_char);
-
- // Scan the rest of the identifier characters.
- while (unicode_cache_->IsIdentifierPart(c0_)) {
- if (c0_ != '\\') {
- uc32 next_char = c0_;
- Advance();
- AddLiteralChar(next_char);
- continue;
- }
- // Fallthrough if no longer able to complete keyword.
- return ScanIdentifierSuffix(&literal);
- }
-
- literal.Complete();
-
- if (next_.literal_chars->is_ascii()) {
- Vector<const char> chars = next_.literal_chars->ascii_literal();
- return KeywordOrIdentifierToken(chars.start(),
- chars.length(),
- harmony_block_scoping_);
- }
-
- return Token::IDENTIFIER;
-}
-
-
-Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) {
- // Scan the rest of the identifier characters.
- while (unicode_cache_->IsIdentifierPart(c0_)) {
- if (c0_ == '\\') {
- uc32 c = ScanIdentifierUnicodeEscape();
- // Only allow legal identifier part characters.
- if (c < 0 ||
- c == '\\' ||
- !unicode_cache_->IsIdentifierPart(c)) {
- return Token::ILLEGAL;
- }
- AddLiteralChar(c);
- } else {
- AddLiteralChar(c0_);
- Advance();
- }
- }
- literal->Complete();
-
- return Token::IDENTIFIER;
-}
-
-
-bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
- // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
- bool in_character_class = false;
-
- // Previous token is either '/' or '/=', in the second case, the
- // pattern starts at =.
- next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
- next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
-
- // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
- // the scanner should pass uninterpreted bodies to the RegExp
- // constructor.
- LiteralScope literal(this);
- if (seen_equal) {
- AddLiteralChar('=');
- }
-
- while (c0_ != '/' || in_character_class) {
- if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
- if (c0_ == '\\') { // Escape sequence.
- AddLiteralCharAdvance();
- if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
- AddLiteralCharAdvance();
- // If the escape allows more characters, i.e., \x??, \u????, or \c?,
- // only "safe" characters are allowed (letters, digits, underscore),
- // otherwise the escape isn't valid and the invalid character has
- // its normal meaning. I.e., we can just continue scanning without
- // worrying whether the following characters are part of the escape
- // or not, since any '/', '\\' or '[' is guaranteed to not be part
- // of the escape sequence.
-
- // TODO(896): At some point, parse RegExps more throughly to capture
- // octal esacpes in strict mode.
- } else { // Unescaped character.
- if (c0_ == '[') in_character_class = true;
- if (c0_ == ']') in_character_class = false;
- AddLiteralCharAdvance();
- }
- }
- Advance(); // consume '/'
-
- literal.Complete();
-
- return true;
-}
-
-
-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() {
- // Scan regular expression flags.
- LiteralScope literal(this);
- while (unicode_cache_->IsIdentifierPart(c0_)) {
- if (c0_ != '\\') {
- AddLiteralCharAdvance();
- } else {
- if (!ScanLiteralUnicodeEscape()) {
- break;
- }
- }
- }
- literal.Complete();
-
- next_.location.end_pos = source_pos() - 1;
- return true;
-}
-
-} } // namespace v8::internal
diff --git a/src/scanner-base.h b/src/scanner-base.h
deleted file mode 100644
index d68d240..0000000
--- a/src/scanner-base.h
+++ /dev/null
@@ -1,562 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Features shared by parsing and pre-parsing scanners.
-
-#ifndef V8_SCANNER_BASE_H_
-#define V8_SCANNER_BASE_H_
-
-#include "allocation.h"
-#include "char-predicates.h"
-#include "checks.h"
-#include "globals.h"
-#include "token.h"
-#include "unicode-inl.h"
-#include "utils.h"
-
-namespace v8 {
-namespace internal {
-
-// Returns the value (0 .. 15) of a hexadecimal character c.
-// If c is not a legal hexadecimal character, returns a value < 0.
-inline int HexValue(uc32 c) {
- c -= '0';
- if (static_cast<unsigned>(c) <= 9) return c;
- c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
- if (static_cast<unsigned>(c) <= 5) return c + 10;
- return -1;
-}
-
-
-// ---------------------------------------------------------------------
-// Buffered stream of characters, using an internal UC16 buffer.
-
-class UC16CharacterStream {
- public:
- UC16CharacterStream() : pos_(0) { }
- virtual ~UC16CharacterStream() { }
-
- // Returns and advances past the next UC16 character in the input
- // stream. If there are no more characters, it returns a negative
- // value.
- inline uc32 Advance() {
- if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
- pos_++;
- return static_cast<uc32>(*(buffer_cursor_++));
- }
- // Note: currently the following increment is necessary to avoid a
- // parser problem! The scanner treats the final kEndOfInput as
- // a character with a position, and does math relative to that
- // position.
- pos_++;
-
- return kEndOfInput;
- }
-
- // Return the current position in the character stream.
- // Starts at zero.
- inline unsigned pos() const { return pos_; }
-
- // Skips forward past the next character_count UC16 characters
- // in the input, or until the end of input if that comes sooner.
- // Returns the number of characters actually skipped. If less
- // than character_count,
- inline unsigned SeekForward(unsigned character_count) {
- unsigned buffered_chars =
- static_cast<unsigned>(buffer_end_ - buffer_cursor_);
- if (character_count <= buffered_chars) {
- buffer_cursor_ += character_count;
- pos_ += character_count;
- return character_count;
- }
- return SlowSeekForward(character_count);
- }
-
- // Pushes back the most recently read UC16 character (or negative
- // value if at end of input), i.e., the value returned by the most recent
- // call to Advance.
- // Must not be used right after calling SeekForward.
- virtual void PushBack(int32_t character) = 0;
-
- protected:
- static const uc32 kEndOfInput = -1;
-
- // Ensures that the buffer_cursor_ points to the character at
- // position pos_ of the input, if possible. If the position
- // is at or after the end of the input, return false. If there
- // are more characters available, return true.
- virtual bool ReadBlock() = 0;
- virtual unsigned SlowSeekForward(unsigned character_count) = 0;
-
- const uc16* buffer_cursor_;
- const uc16* buffer_end_;
- unsigned pos_;
-};
-
-
-class UnicodeCache {
-// ---------------------------------------------------------------------
-// Caching predicates used by scanners.
- public:
- UnicodeCache() {}
- typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
-
- StaticResource<Utf8Decoder>* utf8_decoder() {
- return &utf8_decoder_;
- }
-
- bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
- bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
- bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
- bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
-
- private:
-
- unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
- unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
- unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
- unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
- StaticResource<Utf8Decoder> utf8_decoder_;
-
- DISALLOW_COPY_AND_ASSIGN(UnicodeCache);
-};
-
-
-// ----------------------------------------------------------------------------
-// LiteralBuffer - Collector of chars of literals.
-
-class LiteralBuffer {
- public:
- LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { }
-
- ~LiteralBuffer() {
- if (backing_store_.length() > 0) {
- backing_store_.Dispose();
- }
- }
-
- inline void AddChar(uc16 character) {
- if (position_ >= backing_store_.length()) ExpandBuffer();
- if (is_ascii_) {
- if (character < kMaxAsciiCharCodeU) {
- backing_store_[position_] = static_cast<byte>(character);
- position_ += kASCIISize;
- return;
- }
- ConvertToUC16();
- }
- *reinterpret_cast<uc16*>(&backing_store_[position_]) = character;
- position_ += kUC16Size;
- }
-
- bool is_ascii() { return is_ascii_; }
-
- Vector<const uc16> uc16_literal() {
- ASSERT(!is_ascii_);
- ASSERT((position_ & 0x1) == 0);
- return Vector<const uc16>(
- reinterpret_cast<const uc16*>(backing_store_.start()),
- position_ >> 1);
- }
-
- Vector<const char> ascii_literal() {
- ASSERT(is_ascii_);
- return Vector<const char>(
- reinterpret_cast<const char*>(backing_store_.start()),
- position_);
- }
-
- int length() {
- return is_ascii_ ? position_ : (position_ >> 1);
- }
-
- void Reset() {
- position_ = 0;
- is_ascii_ = true;
- }
- private:
- static const int kInitialCapacity = 16;
- static const int kGrowthFactory = 4;
- static const int kMinConversionSlack = 256;
- static const int kMaxGrowth = 1 * MB;
- inline int NewCapacity(int min_capacity) {
- int capacity = Max(min_capacity, backing_store_.length());
- int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
- return new_capacity;
- }
-
- void ExpandBuffer() {
- Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
- memcpy(new_store.start(), backing_store_.start(), position_);
- backing_store_.Dispose();
- backing_store_ = new_store;
- }
-
- void ConvertToUC16() {
- ASSERT(is_ascii_);
- Vector<byte> new_store;
- int new_content_size = position_ * kUC16Size;
- if (new_content_size >= backing_store_.length()) {
- // Ensure room for all currently read characters as UC16 as well
- // as the character about to be stored.
- new_store = Vector<byte>::New(NewCapacity(new_content_size));
- } else {
- new_store = backing_store_;
- }
- char* src = reinterpret_cast<char*>(backing_store_.start());
- uc16* dst = reinterpret_cast<uc16*>(new_store.start());
- for (int i = position_ - 1; i >= 0; i--) {
- dst[i] = src[i];
- }
- if (new_store.start() != backing_store_.start()) {
- backing_store_.Dispose();
- backing_store_ = new_store;
- }
- position_ = new_content_size;
- is_ascii_ = false;
- }
-
- bool is_ascii_;
- int position_;
- Vector<byte> backing_store_;
-
- DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
-};
-
-
-// ----------------------------------------------------------------------------
-// Scanner base-class.
-
-// Generic functionality used by both JSON and JavaScript scanners.
-class Scanner {
- public:
- // -1 is outside of the range of any real source code.
- static const int kNoOctalLocation = -1;
-
- typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
-
- class LiteralScope {
- public:
- explicit LiteralScope(Scanner* self);
- ~LiteralScope();
- void Complete();
-
- private:
- Scanner* scanner_;
- bool complete_;
- };
-
- explicit Scanner(UnicodeCache* scanner_contants);
-
- // Returns the current token again.
- Token::Value current_token() { return current_.token; }
-
- // One token look-ahead (past the token returned by Next()).
- Token::Value peek() const { return next_.token; }
-
- struct Location {
- Location(int b, int e) : beg_pos(b), end_pos(e) { }
- Location() : beg_pos(0), end_pos(0) { }
-
- bool IsValid() const {
- return beg_pos >= 0 && end_pos >= beg_pos;
- }
-
- static Location invalid() { return Location(-1, -1); }
-
- int beg_pos;
- int end_pos;
- };
-
- // Returns the location information for the current token
- // (the token returned by Next()).
- Location location() const { return current_.location; }
- Location peek_location() const { return next_.location; }
-
- // Returns the literal string, if any, for the current token (the
- // token returned by Next()). The string is 0-terminated and in
- // UTF-8 format; they may contain 0-characters. Literal strings are
- // collected for identifiers, strings, and numbers.
- // These functions only give the correct result if the literal
- // was scanned between calls to StartLiteral() and TerminateLiteral().
- bool is_literal_ascii() {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->is_ascii();
- }
- Vector<const char> literal_ascii_string() {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->ascii_literal();
- }
- Vector<const uc16> literal_uc16_string() {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->uc16_literal();
- }
- int literal_length() const {
- ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->length();
- }
-
- bool literal_contains_escapes() const {
- Location location = current_.location;
- int source_length = (location.end_pos - location.beg_pos);
- if (current_.token == Token::STRING) {
- // Subtract delimiters.
- source_length -= 2;
- }
- return current_.literal_chars->length() != source_length;
- }
-
- // Returns the literal string for the next token (the token that
- // would be returned if Next() were called).
- bool is_next_literal_ascii() {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->is_ascii();
- }
- Vector<const char> next_literal_ascii_string() {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->ascii_literal();
- }
- Vector<const uc16> next_literal_uc16_string() {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->uc16_literal();
- }
- int next_literal_length() const {
- ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->length();
- }
-
- static const int kCharacterLookaheadBufferSize = 1;
-
- protected:
- // The current and look-ahead token.
- struct TokenDesc {
- Token::Value token;
- Location location;
- LiteralBuffer* literal_chars;
- };
-
- // Call this after setting source_ to the input.
- void Init() {
- // Set c0_ (one character ahead)
- STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
- Advance();
- // Initialize current_ to not refer to a literal.
- current_.literal_chars = NULL;
- }
-
- // Literal buffer support
- inline void StartLiteral() {
- LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ?
- &literal_buffer2_ : &literal_buffer1_;
- free_buffer->Reset();
- next_.literal_chars = free_buffer;
- }
-
- inline void AddLiteralChar(uc32 c) {
- ASSERT_NOT_NULL(next_.literal_chars);
- next_.literal_chars->AddChar(c);
- }
-
- // Complete scanning of a literal.
- inline void TerminateLiteral() {
- // Does nothing in the current implementation.
- }
-
- // Stops scanning of a literal and drop the collected characters,
- // e.g., due to an encountered error.
- inline void DropLiteral() {
- next_.literal_chars = NULL;
- }
-
- inline void AddLiteralCharAdvance() {
- AddLiteralChar(c0_);
- Advance();
- }
-
- // Low-level scanning support.
- void Advance() { c0_ = source_->Advance(); }
- void PushBack(uc32 ch) {
- source_->PushBack(c0_);
- c0_ = ch;
- }
-
- inline Token::Value Select(Token::Value tok) {
- Advance();
- return tok;
- }
-
- inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
- Advance();
- if (c0_ == next) {
- Advance();
- return then;
- } else {
- return else_;
- }
- }
-
- uc32 ScanHexNumber(int expected_length);
-
- // Return the current source position.
- int source_pos() {
- return source_->pos() - kCharacterLookaheadBufferSize;
- }
-
- UnicodeCache* unicode_cache_;
-
- // Buffers collecting literal strings, numbers, etc.
- LiteralBuffer literal_buffer1_;
- LiteralBuffer literal_buffer2_;
-
- TokenDesc current_; // desc for current token (as returned by Next())
- TokenDesc next_; // desc for next token (one token look-ahead)
-
- // Input stream. Must be initialized to an UC16CharacterStream.
- UC16CharacterStream* source_;
-
- // One Unicode character look-ahead; c0_ < 0 at the end of the input.
- uc32 c0_;
-};
-
-// ----------------------------------------------------------------------------
-// JavaScriptScanner - base logic for JavaScript scanning.
-
-class JavaScriptScanner : public Scanner {
- public:
- // A LiteralScope that disables recording of some types of JavaScript
- // literals. If the scanner is configured to not record the specific
- // type of literal, the scope will not call StartLiteral.
- class LiteralScope {
- public:
- explicit LiteralScope(JavaScriptScanner* self)
- : scanner_(self), complete_(false) {
- scanner_->StartLiteral();
- }
- ~LiteralScope() {
- if (!complete_) scanner_->DropLiteral();
- }
- void Complete() {
- scanner_->TerminateLiteral();
- complete_ = true;
- }
-
- private:
- JavaScriptScanner* scanner_;
- bool complete_;
- };
-
- explicit JavaScriptScanner(UnicodeCache* scanner_contants);
-
- void Initialize(UC16CharacterStream* source);
-
- // Returns the next token.
- Token::Value Next();
-
- // Returns true if there was a line terminator before the peek'ed token,
- // possibly inside a multi-line comment.
- bool HasAnyLineTerminatorBeforeNext() const {
- return has_line_terminator_before_next_ ||
- has_multiline_comment_before_next_;
- }
-
- // Scans the input as a regular expression pattern, previous
- // character(s) must be /(=). Returns true if a pattern is scanned.
- bool ScanRegExpPattern(bool seen_equal);
- // Returns true if regexp flags are scanned (always since flags can
- // be empty).
- bool ScanRegExpFlags();
-
- // Tells whether the buffer contains an identifier (no escapes).
- // Used for checking if a property name is an identifier.
- static bool IsIdentifier(unibrow::CharacterStream* buffer);
-
- // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
- uc32 ScanOctalEscape(uc32 c, int length);
-
- // Returns the location of the last seen octal literal
- Location octal_position() const { return octal_pos_; }
- void clear_octal_position() { octal_pos_ = Location::invalid(); }
-
- // Seek forward to the given position. This operation does not
- // work in general, for instance when there are pushed back
- // characters, but works for seeking forward until simple delimiter
- // tokens, which is what it is used for.
- void SeekForward(int pos);
-
- bool HarmonyBlockScoping() const {
- return harmony_block_scoping_;
- }
- void SetHarmonyBlockScoping(bool block_scoping) {
- harmony_block_scoping_ = block_scoping;
- }
-
-
- protected:
- bool SkipWhiteSpace();
- Token::Value SkipSingleLineComment();
- Token::Value SkipMultiLineComment();
-
- // Scans a single JavaScript token.
- void Scan();
-
- void ScanDecimalDigits();
- Token::Value ScanNumber(bool seen_period);
- Token::Value ScanIdentifierOrKeyword();
- Token::Value ScanIdentifierSuffix(LiteralScope* literal);
-
- void ScanEscape();
- Token::Value ScanString();
-
- // Scans a possible HTML comment -- begins with '<!'.
- Token::Value ScanHtmlComment();
-
- // Decodes a unicode escape-sequence which is part of an identifier.
- // If the escape sequence cannot be decoded the result is kBadChar.
- uc32 ScanIdentifierUnicodeEscape();
- // Recognizes a uniocde escape-sequence and adds its characters,
- // uninterpreted, to the current literal. Used for parsing RegExp
- // flags.
- bool ScanLiteralUnicodeEscape();
-
- // Start position of the octal literal last scanned.
- Location octal_pos_;
-
- // Whether there is a line terminator whitespace character after
- // the current token, and before the next. Does not count newlines
- // inside multiline comments.
- bool has_line_terminator_before_next_;
- // Whether there is a multi-line comment that contains a
- // line-terminator after the current token, and before the next.
- bool has_multiline_comment_before_next_;
- // Whether we scan 'let' as a keyword for harmony block scoped
- // let bindings.
- bool harmony_block_scoping_;
-};
-
-} } // namespace v8::internal
-
-#endif // V8_SCANNER_BASE_H_
diff --git a/src/scanner-character-streams.cc b/src/scanner-character-streams.cc
new file mode 100644
index 0000000..ee10703
--- /dev/null
+++ b/src/scanner-character-streams.cc
@@ -0,0 +1,307 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "scanner-character-streams.h"
+
+#include "handles.h"
+#include "unicode-inl.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// BufferedUC16CharacterStreams
+
+BufferedUC16CharacterStream::BufferedUC16CharacterStream()
+ : UC16CharacterStream(),
+ pushback_limit_(NULL) {
+ // Initialize buffer as being empty. First read will fill the buffer.
+ buffer_cursor_ = buffer_;
+ buffer_end_ = buffer_;
+}
+
+BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { }
+
+void BufferedUC16CharacterStream::PushBack(uc32 character) {
+ if (character == kEndOfInput) {
+ pos_--;
+ return;
+ }
+ if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) {
+ // buffer_ is writable, buffer_cursor_ is const pointer.
+ buffer_[--buffer_cursor_ - buffer_] = static_cast<uc16>(character);
+ pos_--;
+ return;
+ }
+ SlowPushBack(static_cast<uc16>(character));
+}
+
+
+void BufferedUC16CharacterStream::SlowPushBack(uc16 character) {
+ // In pushback mode, the end of the buffer contains pushback,
+ // and the start of the buffer (from buffer start to pushback_limit_)
+ // contains valid data that comes just after the pushback.
+ // We NULL the pushback_limit_ if pushing all the way back to the
+ // start of the buffer.
+
+ if (pushback_limit_ == NULL) {
+ // Enter pushback mode.
+ pushback_limit_ = buffer_end_;
+ buffer_end_ = buffer_ + kBufferSize;
+ buffer_cursor_ = buffer_end_;
+ }
+ // Ensure that there is room for at least one pushback.
+ ASSERT(buffer_cursor_ > buffer_);
+ ASSERT(pos_ > 0);
+ buffer_[--buffer_cursor_ - buffer_] = character;
+ if (buffer_cursor_ == buffer_) {
+ pushback_limit_ = NULL;
+ } else if (buffer_cursor_ < pushback_limit_) {
+ pushback_limit_ = buffer_cursor_;
+ }
+ pos_--;
+}
+
+
+bool BufferedUC16CharacterStream::ReadBlock() {
+ buffer_cursor_ = buffer_;
+ if (pushback_limit_ != NULL) {
+ // Leave pushback mode.
+ buffer_end_ = pushback_limit_;
+ pushback_limit_ = NULL;
+ // If there were any valid characters left at the
+ // start of the buffer, use those.
+ if (buffer_cursor_ < buffer_end_) return true;
+ // Otherwise read a new block.
+ }
+ unsigned length = FillBuffer(pos_, kBufferSize);
+ buffer_end_ = buffer_ + length;
+ return length > 0;
+}
+
+
+unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) {
+ // Leave pushback mode (i.e., ignore that there might be valid data
+ // in the buffer before the pushback_limit_ point).
+ pushback_limit_ = NULL;
+ return BufferSeekForward(delta);
+}
+
+// ----------------------------------------------------------------------------
+// GenericStringUC16CharacterStream
+
+
+GenericStringUC16CharacterStream::GenericStringUC16CharacterStream(
+ Handle<String> data,
+ unsigned start_position,
+ unsigned end_position)
+ : string_(data),
+ length_(end_position) {
+ ASSERT(end_position >= start_position);
+ buffer_cursor_ = buffer_;
+ buffer_end_ = buffer_;
+ pos_ = start_position;
+}
+
+
+GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { }
+
+
+unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) {
+ unsigned old_pos = pos_;
+ pos_ = Min(pos_ + delta, length_);
+ ReadBlock();
+ return pos_ - old_pos;
+}
+
+
+unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos,
+ unsigned length) {
+ if (from_pos >= length_) return 0;
+ if (from_pos + length > length_) {
+ length = length_ - from_pos;
+ }
+ String::WriteToFlat<uc16>(*string_, buffer_, from_pos, from_pos + length);
+ return length;
+}
+
+
+// ----------------------------------------------------------------------------
+// Utf8ToUC16CharacterStream
+Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data,
+ unsigned length)
+ : BufferedUC16CharacterStream(),
+ raw_data_(data),
+ raw_data_length_(length),
+ raw_data_pos_(0),
+ raw_character_position_(0) {
+ ReadBlock();
+}
+
+
+Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { }
+
+
+unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) {
+ unsigned old_pos = pos_;
+ unsigned target_pos = pos_ + delta;
+ SetRawPosition(target_pos);
+ pos_ = raw_character_position_;
+ ReadBlock();
+ return pos_ - old_pos;
+}
+
+
+unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position,
+ unsigned length) {
+ static const unibrow::uchar kMaxUC16Character = 0xffff;
+ SetRawPosition(char_position);
+ if (raw_character_position_ != char_position) {
+ // char_position was not a valid position in the stream (hit the end
+ // while spooling to it).
+ return 0u;
+ }
+ unsigned i = 0;
+ while (i < length) {
+ if (raw_data_pos_ == raw_data_length_) break;
+ unibrow::uchar c = raw_data_[raw_data_pos_];
+ if (c <= unibrow::Utf8::kMaxOneByteChar) {
+ raw_data_pos_++;
+ } else {
+ c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,
+ raw_data_length_ - raw_data_pos_,
+ &raw_data_pos_);
+ // Don't allow characters outside of the BMP.
+ if (c > kMaxUC16Character) {
+ c = unibrow::Utf8::kBadChar;
+ }
+ }
+ buffer_[i++] = static_cast<uc16>(c);
+ }
+ raw_character_position_ = char_position + i;
+ return i;
+}
+
+
+static const byte kUtf8MultiByteMask = 0xC0;
+static const byte kUtf8MultiByteCharStart = 0xC0;
+static const byte kUtf8MultiByteCharFollower = 0x80;
+
+
+#ifdef DEBUG
+static bool IsUtf8MultiCharacterStart(byte first_byte) {
+ return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart;
+}
+#endif
+
+
+static bool IsUtf8MultiCharacterFollower(byte later_byte) {
+ return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower;
+}
+
+
+// Move the cursor back to point at the preceding UTF-8 character start
+// in the buffer.
+static inline void Utf8CharacterBack(const byte* buffer, unsigned* cursor) {
+ byte character = buffer[--*cursor];
+ if (character > unibrow::Utf8::kMaxOneByteChar) {
+ ASSERT(IsUtf8MultiCharacterFollower(character));
+ // Last byte of a multi-byte character encoding. Step backwards until
+ // pointing to the first byte of the encoding, recognized by having the
+ // top two bits set.
+ while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { }
+ ASSERT(IsUtf8MultiCharacterStart(buffer[*cursor]));
+ }
+}
+
+
+// Move the cursor forward to point at the next following UTF-8 character start
+// in the buffer.
+static inline void Utf8CharacterForward(const byte* buffer, unsigned* cursor) {
+ byte character = buffer[(*cursor)++];
+ if (character > unibrow::Utf8::kMaxOneByteChar) {
+ // First character of a multi-byte character encoding.
+ // The number of most-significant one-bits determines the length of the
+ // encoding:
+ // 110..... - (0xCx, 0xDx) one additional byte (minimum).
+ // 1110.... - (0xEx) two additional bytes.
+ // 11110... - (0xFx) three additional bytes (maximum).
+ ASSERT(IsUtf8MultiCharacterStart(character));
+ // Additional bytes is:
+ // 1 if value in range 0xC0 .. 0xDF.
+ // 2 if value in range 0xE0 .. 0xEF.
+ // 3 if value in range 0xF0 .. 0xF7.
+ // Encode that in a single value.
+ unsigned additional_bytes =
+ ((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03;
+ *cursor += additional_bytes;
+ ASSERT(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes]));
+ }
+}
+
+
+void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) {
+ if (raw_character_position_ > target_position) {
+ // Spool backwards in utf8 buffer.
+ do {
+ Utf8CharacterBack(raw_data_, &raw_data_pos_);
+ raw_character_position_--;
+ } while (raw_character_position_ > target_position);
+ return;
+ }
+ // Spool forwards in the utf8 buffer.
+ while (raw_character_position_ < target_position) {
+ if (raw_data_pos_ == raw_data_length_) return;
+ Utf8CharacterForward(raw_data_, &raw_data_pos_);
+ raw_character_position_++;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// ExternalTwoByteStringUC16CharacterStream
+
+ExternalTwoByteStringUC16CharacterStream::
+ ~ExternalTwoByteStringUC16CharacterStream() { }
+
+
+ExternalTwoByteStringUC16CharacterStream
+ ::ExternalTwoByteStringUC16CharacterStream(
+ Handle<ExternalTwoByteString> data,
+ int start_position,
+ int end_position)
+ : UC16CharacterStream(),
+ source_(data),
+ raw_data_(data->GetTwoByteData(start_position)) {
+ buffer_cursor_ = raw_data_,
+ buffer_end_ = raw_data_ + (end_position - start_position);
+ pos_ = start_position;
+}
+
+} } // namespace v8::internal
diff --git a/src/scanner-character-streams.h b/src/scanner-character-streams.h
new file mode 100644
index 0000000..5c4ea2c
--- /dev/null
+++ b/src/scanner-character-streams.h
@@ -0,0 +1,129 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_SCANNER_CHARACTER_STREAMS_H_
+#define V8_SCANNER_CHARACTER_STREAMS_H_
+
+#include "scanner.h"
+
+namespace v8 {
+namespace internal {
+
+// A buffered character stream based on a random access character
+// source (ReadBlock can be called with pos_ pointing to any position,
+// even positions before the current).
+class BufferedUC16CharacterStream: public UC16CharacterStream {
+ public:
+ BufferedUC16CharacterStream();
+ virtual ~BufferedUC16CharacterStream();
+
+ virtual void PushBack(uc32 character);
+
+ protected:
+ static const unsigned kBufferSize = 512;
+ static const unsigned kPushBackStepSize = 16;
+
+ virtual unsigned SlowSeekForward(unsigned delta);
+ virtual bool ReadBlock();
+ virtual void SlowPushBack(uc16 character);
+
+ virtual unsigned BufferSeekForward(unsigned delta) = 0;
+ virtual unsigned FillBuffer(unsigned position, unsigned length) = 0;
+
+ const uc16* pushback_limit_;
+ uc16 buffer_[kBufferSize];
+};
+
+
+// Generic string stream.
+class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
+ public:
+ GenericStringUC16CharacterStream(Handle<String> data,
+ unsigned start_position,
+ unsigned end_position);
+ virtual ~GenericStringUC16CharacterStream();
+
+ protected:
+ virtual unsigned BufferSeekForward(unsigned delta);
+ virtual unsigned FillBuffer(unsigned position, unsigned length);
+
+ Handle<String> string_;
+ unsigned start_position_;
+ unsigned length_;
+};
+
+
+// UC16 stream based on a literal UTF-8 string.
+class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
+ public:
+ Utf8ToUC16CharacterStream(const byte* data, unsigned length);
+ virtual ~Utf8ToUC16CharacterStream();
+
+ protected:
+ virtual unsigned BufferSeekForward(unsigned delta);
+ virtual unsigned FillBuffer(unsigned char_position, unsigned length);
+ void SetRawPosition(unsigned char_position);
+
+ const byte* raw_data_;
+ unsigned raw_data_length_; // Measured in bytes, not characters.
+ unsigned raw_data_pos_;
+ // The character position of the character at raw_data[raw_data_pos_].
+ // Not necessarily the same as pos_.
+ unsigned raw_character_position_;
+};
+
+
+// UTF16 buffer to read characters from an external string.
+class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
+ public:
+ ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
+ int start_position,
+ int end_position);
+ virtual ~ExternalTwoByteStringUC16CharacterStream();
+
+ virtual void PushBack(uc32 character) {
+ ASSERT(buffer_cursor_ > raw_data_);
+ buffer_cursor_--;
+ pos_--;
+ }
+
+ protected:
+ virtual unsigned SlowSeekForward(unsigned delta) {
+ // Fast case always handles seeking.
+ return 0;
+ }
+ virtual bool ReadBlock() {
+ // Entire string is read at start.
+ return false;
+ }
+ Handle<ExternalTwoByteString> source_;
+ const uc16* raw_data_; // Pointer to the actual array of characters.
+};
+
+} } // namespace v8::internal
+
+#endif // V8_SCANNER_CHARACTER_STREAMS_H_
diff --git a/src/scanner.cc b/src/scanner.cc
index 5919073..69ea8ae 100644
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -25,287 +25,17 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "v8.h"
+// Features shared by parsing and pre-parsing scanners.
-#include "ast.h"
-#include "handles.h"
#include "scanner.h"
-#include "unicode-inl.h"
+
+#include "../include/v8stdint.h"
+#include "char-predicates-inl.h"
namespace v8 {
namespace internal {
// ----------------------------------------------------------------------------
-// BufferedUC16CharacterStreams
-
-BufferedUC16CharacterStream::BufferedUC16CharacterStream()
- : UC16CharacterStream(),
- pushback_limit_(NULL) {
- // Initialize buffer as being empty. First read will fill the buffer.
- buffer_cursor_ = buffer_;
- buffer_end_ = buffer_;
-}
-
-BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { }
-
-void BufferedUC16CharacterStream::PushBack(uc32 character) {
- if (character == kEndOfInput) {
- pos_--;
- return;
- }
- if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) {
- // buffer_ is writable, buffer_cursor_ is const pointer.
- buffer_[--buffer_cursor_ - buffer_] = static_cast<uc16>(character);
- pos_--;
- return;
- }
- SlowPushBack(static_cast<uc16>(character));
-}
-
-
-void BufferedUC16CharacterStream::SlowPushBack(uc16 character) {
- // In pushback mode, the end of the buffer contains pushback,
- // and the start of the buffer (from buffer start to pushback_limit_)
- // contains valid data that comes just after the pushback.
- // We NULL the pushback_limit_ if pushing all the way back to the
- // start of the buffer.
-
- if (pushback_limit_ == NULL) {
- // Enter pushback mode.
- pushback_limit_ = buffer_end_;
- buffer_end_ = buffer_ + kBufferSize;
- buffer_cursor_ = buffer_end_;
- }
- // Ensure that there is room for at least one pushback.
- ASSERT(buffer_cursor_ > buffer_);
- ASSERT(pos_ > 0);
- buffer_[--buffer_cursor_ - buffer_] = character;
- if (buffer_cursor_ == buffer_) {
- pushback_limit_ = NULL;
- } else if (buffer_cursor_ < pushback_limit_) {
- pushback_limit_ = buffer_cursor_;
- }
- pos_--;
-}
-
-
-bool BufferedUC16CharacterStream::ReadBlock() {
- buffer_cursor_ = buffer_;
- if (pushback_limit_ != NULL) {
- // Leave pushback mode.
- buffer_end_ = pushback_limit_;
- pushback_limit_ = NULL;
- // If there were any valid characters left at the
- // start of the buffer, use those.
- if (buffer_cursor_ < buffer_end_) return true;
- // Otherwise read a new block.
- }
- unsigned length = FillBuffer(pos_, kBufferSize);
- buffer_end_ = buffer_ + length;
- return length > 0;
-}
-
-
-unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) {
- // Leave pushback mode (i.e., ignore that there might be valid data
- // in the buffer before the pushback_limit_ point).
- pushback_limit_ = NULL;
- return BufferSeekForward(delta);
-}
-
-// ----------------------------------------------------------------------------
-// GenericStringUC16CharacterStream
-
-
-GenericStringUC16CharacterStream::GenericStringUC16CharacterStream(
- Handle<String> data,
- unsigned start_position,
- unsigned end_position)
- : string_(data),
- length_(end_position) {
- ASSERT(end_position >= start_position);
- buffer_cursor_ = buffer_;
- buffer_end_ = buffer_;
- pos_ = start_position;
-}
-
-
-GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { }
-
-
-unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) {
- unsigned old_pos = pos_;
- pos_ = Min(pos_ + delta, length_);
- ReadBlock();
- return pos_ - old_pos;
-}
-
-
-unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos,
- unsigned length) {
- if (from_pos >= length_) return 0;
- if (from_pos + length > length_) {
- length = length_ - from_pos;
- }
- String::WriteToFlat<uc16>(*string_, buffer_, from_pos, from_pos + length);
- return length;
-}
-
-
-// ----------------------------------------------------------------------------
-// Utf8ToUC16CharacterStream
-Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data,
- unsigned length)
- : BufferedUC16CharacterStream(),
- raw_data_(data),
- raw_data_length_(length),
- raw_data_pos_(0),
- raw_character_position_(0) {
- ReadBlock();
-}
-
-
-Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { }
-
-
-unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) {
- unsigned old_pos = pos_;
- unsigned target_pos = pos_ + delta;
- SetRawPosition(target_pos);
- pos_ = raw_character_position_;
- ReadBlock();
- return pos_ - old_pos;
-}
-
-
-unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position,
- unsigned length) {
- static const unibrow::uchar kMaxUC16Character = 0xffff;
- SetRawPosition(char_position);
- if (raw_character_position_ != char_position) {
- // char_position was not a valid position in the stream (hit the end
- // while spooling to it).
- return 0u;
- }
- unsigned i = 0;
- while (i < length) {
- if (raw_data_pos_ == raw_data_length_) break;
- unibrow::uchar c = raw_data_[raw_data_pos_];
- if (c <= unibrow::Utf8::kMaxOneByteChar) {
- raw_data_pos_++;
- } else {
- c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,
- raw_data_length_ - raw_data_pos_,
- &raw_data_pos_);
- // Don't allow characters outside of the BMP.
- if (c > kMaxUC16Character) {
- c = unibrow::Utf8::kBadChar;
- }
- }
- buffer_[i++] = static_cast<uc16>(c);
- }
- raw_character_position_ = char_position + i;
- return i;
-}
-
-
-static const byte kUtf8MultiByteMask = 0xC0;
-static const byte kUtf8MultiByteCharStart = 0xC0;
-static const byte kUtf8MultiByteCharFollower = 0x80;
-
-
-#ifdef DEBUG
-static bool IsUtf8MultiCharacterStart(byte first_byte) {
- return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart;
-}
-#endif
-
-
-static bool IsUtf8MultiCharacterFollower(byte later_byte) {
- return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower;
-}
-
-
-// Move the cursor back to point at the preceding UTF-8 character start
-// in the buffer.
-static inline void Utf8CharacterBack(const byte* buffer, unsigned* cursor) {
- byte character = buffer[--*cursor];
- if (character > unibrow::Utf8::kMaxOneByteChar) {
- ASSERT(IsUtf8MultiCharacterFollower(character));
- // Last byte of a multi-byte character encoding. Step backwards until
- // pointing to the first byte of the encoding, recognized by having the
- // top two bits set.
- while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { }
- ASSERT(IsUtf8MultiCharacterStart(buffer[*cursor]));
- }
-}
-
-
-// Move the cursor forward to point at the next following UTF-8 character start
-// in the buffer.
-static inline void Utf8CharacterForward(const byte* buffer, unsigned* cursor) {
- byte character = buffer[(*cursor)++];
- if (character > unibrow::Utf8::kMaxOneByteChar) {
- // First character of a multi-byte character encoding.
- // The number of most-significant one-bits determines the length of the
- // encoding:
- // 110..... - (0xCx, 0xDx) one additional byte (minimum).
- // 1110.... - (0xEx) two additional bytes.
- // 11110... - (0xFx) three additional bytes (maximum).
- ASSERT(IsUtf8MultiCharacterStart(character));
- // Additional bytes is:
- // 1 if value in range 0xC0 .. 0xDF.
- // 2 if value in range 0xE0 .. 0xEF.
- // 3 if value in range 0xF0 .. 0xF7.
- // Encode that in a single value.
- unsigned additional_bytes =
- ((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03;
- *cursor += additional_bytes;
- ASSERT(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes]));
- }
-}
-
-
-void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) {
- if (raw_character_position_ > target_position) {
- // Spool backwards in utf8 buffer.
- do {
- Utf8CharacterBack(raw_data_, &raw_data_pos_);
- raw_character_position_--;
- } while (raw_character_position_ > target_position);
- return;
- }
- // Spool forwards in the utf8 buffer.
- while (raw_character_position_ < target_position) {
- if (raw_data_pos_ == raw_data_length_) return;
- Utf8CharacterForward(raw_data_, &raw_data_pos_);
- raw_character_position_++;
- }
-}
-
-
-// ----------------------------------------------------------------------------
-// ExternalTwoByteStringUC16CharacterStream
-
-ExternalTwoByteStringUC16CharacterStream::
- ~ExternalTwoByteStringUC16CharacterStream() { }
-
-
-ExternalTwoByteStringUC16CharacterStream
- ::ExternalTwoByteStringUC16CharacterStream(
- Handle<ExternalTwoByteString> data,
- int start_position,
- int end_position)
- : UC16CharacterStream(),
- source_(data),
- raw_data_(data->GetTwoByteData(start_position)) {
- buffer_cursor_ = raw_data_,
- buffer_end_ = raw_data_ + (end_position - start_position);
- pos_ = start_position;
-}
-
-
-// ----------------------------------------------------------------------------
// Scanner::LiteralScope
Scanner::LiteralScope::LiteralScope(Scanner* self)
@@ -324,4 +54,1057 @@
complete_ = true;
}
+// ----------------------------------------------------------------------------
+// Scanner
+
+Scanner::Scanner(UnicodeCache* unicode_cache)
+ : unicode_cache_(unicode_cache) { }
+
+
+uc32 Scanner::ScanHexNumber(int expected_length) {
+ ASSERT(expected_length <= 4); // prevent overflow
+
+ uc32 digits[4] = { 0, 0, 0, 0 };
+ uc32 x = 0;
+ for (int i = 0; i < expected_length; i++) {
+ digits[i] = c0_;
+ int d = HexValue(c0_);
+ if (d < 0) {
+ // According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes
+ // should be illegal, but other JS VMs just return the
+ // non-escaped version of the original character.
+
+ // Push back digits that we have advanced past.
+ for (int j = i-1; j >= 0; j--) {
+ PushBack(digits[j]);
+ }
+ return -1;
+ }
+ x = x * 16 + d;
+ Advance();
+ }
+
+ return x;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// JavaScriptScanner
+
+JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants)
+ : Scanner(scanner_contants),
+ octal_pos_(Location::invalid()),
+ harmony_block_scoping_(false) { }
+
+
+void JavaScriptScanner::Initialize(UC16CharacterStream* source) {
+ source_ = source;
+ // Need to capture identifiers in order to recognize "get" and "set"
+ // in object literals.
+ Init();
+ // Skip initial whitespace allowing HTML comment ends just like
+ // after a newline and scan first token.
+ has_line_terminator_before_next_ = true;
+ SkipWhiteSpace();
+ Scan();
+}
+
+
+// Ensure that tokens can be stored in a byte.
+STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
+
+// Table of one-character tokens, by character (0x00..0x7f only).
+static const byte one_char_tokens[] = {
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LPAREN, // 0x28
+ Token::RPAREN, // 0x29
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COMMA, // 0x2c
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COLON, // 0x3a
+ Token::SEMICOLON, // 0x3b
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::CONDITIONAL, // 0x3f
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACK, // 0x5b
+ Token::ILLEGAL,
+ Token::RBRACK, // 0x5d
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACE, // 0x7b
+ Token::ILLEGAL,
+ Token::RBRACE, // 0x7d
+ Token::BIT_NOT, // 0x7e
+ Token::ILLEGAL
+};
+
+
+Token::Value JavaScriptScanner::Next() {
+ current_ = next_;
+ has_line_terminator_before_next_ = false;
+ has_multiline_comment_before_next_ = false;
+ if (static_cast<unsigned>(c0_) <= 0x7f) {
+ Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]);
+ if (token != Token::ILLEGAL) {
+ int pos = source_pos();
+ next_.token = token;
+ next_.location.beg_pos = pos;
+ next_.location.end_pos = pos + 1;
+ Advance();
+ return current_.token;
+ }
+ }
+ Scan();
+ return current_.token;
+}
+
+
+static inline bool IsByteOrderMark(uc32 c) {
+ // The Unicode value U+FFFE is guaranteed never to be assigned as a
+ // Unicode character; this implies that in a Unicode context the
+ // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF
+ // character expressed in little-endian byte order (since it could
+ // not be a U+FFFE character expressed in big-endian byte
+ // order). Nevertheless, we check for it to be compatible with
+ // Spidermonkey.
+ return c == 0xFEFF || c == 0xFFFE;
+}
+
+
+bool JavaScriptScanner::SkipWhiteSpace() {
+ int start_position = source_pos();
+
+ while (true) {
+ // We treat byte-order marks (BOMs) as whitespace for better
+ // compatibility with Spidermonkey and other JavaScript engines.
+ while (unicode_cache_->IsWhiteSpace(c0_) || IsByteOrderMark(c0_)) {
+ // IsWhiteSpace() includes line terminators!
+ if (unicode_cache_->IsLineTerminator(c0_)) {
+ // Ignore line terminators, but remember them. This is necessary
+ // for automatic semicolon insertion.
+ has_line_terminator_before_next_ = true;
+ }
+ Advance();
+ }
+
+ // If there is an HTML comment end '-->' at the beginning of a
+ // line (with only whitespace in front of it), we treat the rest
+ // of the line as a comment. This is in line with the way
+ // SpiderMonkey handles it.
+ if (c0_ == '-' && has_line_terminator_before_next_) {
+ Advance();
+ if (c0_ == '-') {
+ Advance();
+ if (c0_ == '>') {
+ // Treat the rest of the line as a comment.
+ SkipSingleLineComment();
+ // Continue skipping white space after the comment.
+ continue;
+ }
+ PushBack('-'); // undo Advance()
+ }
+ PushBack('-'); // undo Advance()
+ }
+ // Return whether or not we skipped any characters.
+ return source_pos() != start_position;
+ }
+}
+
+
+Token::Value JavaScriptScanner::SkipSingleLineComment() {
+ Advance();
+
+ // The line terminator at the end of the line is not considered
+ // to be part of the single-line comment; it is recognized
+ // separately by the lexical grammar and becomes part of the
+ // stream of input elements for the syntactic grammar (see
+ // ECMA-262, section 7.4).
+ while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) {
+ Advance();
+ }
+
+ return Token::WHITESPACE;
+}
+
+
+Token::Value JavaScriptScanner::SkipMultiLineComment() {
+ ASSERT(c0_ == '*');
+ Advance();
+
+ while (c0_ >= 0) {
+ uc32 ch = c0_;
+ Advance();
+ if (unicode_cache_->IsLineTerminator(ch)) {
+ // Following ECMA-262, section 7.4, a comment containing
+ // a newline will make the comment count as a line-terminator.
+ has_multiline_comment_before_next_ = true;
+ }
+ // If we have reached the end of the multi-line comment, we
+ // consume the '/' and insert a whitespace. This way all
+ // multi-line comments are treated as whitespace.
+ if (ch == '*' && c0_ == '/') {
+ c0_ = ' ';
+ return Token::WHITESPACE;
+ }
+ }
+
+ // Unterminated multi-line comment.
+ return Token::ILLEGAL;
+}
+
+
+Token::Value JavaScriptScanner::ScanHtmlComment() {
+ // Check for <!-- comments.
+ ASSERT(c0_ == '!');
+ Advance();
+ if (c0_ == '-') {
+ Advance();
+ if (c0_ == '-') return SkipSingleLineComment();
+ PushBack('-'); // undo Advance()
+ }
+ PushBack('!'); // undo Advance()
+ ASSERT(c0_ == '!');
+ return Token::LT;
+}
+
+
+void JavaScriptScanner::Scan() {
+ next_.literal_chars = NULL;
+ Token::Value token;
+ do {
+ // Remember the position of the next token
+ next_.location.beg_pos = source_pos();
+
+ switch (c0_) {
+ case ' ':
+ case '\t':
+ Advance();
+ token = Token::WHITESPACE;
+ break;
+
+ case '\n':
+ Advance();
+ has_line_terminator_before_next_ = true;
+ token = Token::WHITESPACE;
+ break;
+
+ case '"': case '\'':
+ token = ScanString();
+ break;
+
+ case '<':
+ // < <= << <<= <!--
+ Advance();
+ if (c0_ == '=') {
+ token = Select(Token::LTE);
+ } else if (c0_ == '<') {
+ token = Select('=', Token::ASSIGN_SHL, Token::SHL);
+ } else if (c0_ == '!') {
+ token = ScanHtmlComment();
+ } else {
+ token = Token::LT;
+ }
+ break;
+
+ case '>':
+ // > >= >> >>= >>> >>>=
+ Advance();
+ if (c0_ == '=') {
+ token = Select(Token::GTE);
+ } else if (c0_ == '>') {
+ // >> >>= >>> >>>=
+ Advance();
+ if (c0_ == '=') {
+ token = Select(Token::ASSIGN_SAR);
+ } else if (c0_ == '>') {
+ token = Select('=', Token::ASSIGN_SHR, Token::SHR);
+ } else {
+ token = Token::SAR;
+ }
+ } else {
+ token = Token::GT;
+ }
+ break;
+
+ case '=':
+ // = == ===
+ Advance();
+ if (c0_ == '=') {
+ token = Select('=', Token::EQ_STRICT, Token::EQ);
+ } else {
+ token = Token::ASSIGN;
+ }
+ break;
+
+ case '!':
+ // ! != !==
+ Advance();
+ if (c0_ == '=') {
+ token = Select('=', Token::NE_STRICT, Token::NE);
+ } else {
+ token = Token::NOT;
+ }
+ break;
+
+ case '+':
+ // + ++ +=
+ Advance();
+ if (c0_ == '+') {
+ token = Select(Token::INC);
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_ADD);
+ } else {
+ token = Token::ADD;
+ }
+ break;
+
+ case '-':
+ // - -- --> -=
+ Advance();
+ if (c0_ == '-') {
+ Advance();
+ if (c0_ == '>' && has_line_terminator_before_next_) {
+ // For compatibility with SpiderMonkey, we skip lines that
+ // start with an HTML comment end '-->'.
+ token = SkipSingleLineComment();
+ } else {
+ token = Token::DEC;
+ }
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_SUB);
+ } else {
+ token = Token::SUB;
+ }
+ break;
+
+ case '*':
+ // * *=
+ token = Select('=', Token::ASSIGN_MUL, Token::MUL);
+ break;
+
+ case '%':
+ // % %=
+ token = Select('=', Token::ASSIGN_MOD, Token::MOD);
+ break;
+
+ case '/':
+ // / // /* /=
+ Advance();
+ if (c0_ == '/') {
+ token = SkipSingleLineComment();
+ } else if (c0_ == '*') {
+ token = SkipMultiLineComment();
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_DIV);
+ } else {
+ token = Token::DIV;
+ }
+ break;
+
+ case '&':
+ // & && &=
+ Advance();
+ if (c0_ == '&') {
+ token = Select(Token::AND);
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_BIT_AND);
+ } else {
+ token = Token::BIT_AND;
+ }
+ break;
+
+ case '|':
+ // | || |=
+ Advance();
+ if (c0_ == '|') {
+ token = Select(Token::OR);
+ } else if (c0_ == '=') {
+ token = Select(Token::ASSIGN_BIT_OR);
+ } else {
+ token = Token::BIT_OR;
+ }
+ break;
+
+ case '^':
+ // ^ ^=
+ token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
+ break;
+
+ case '.':
+ // . Number
+ Advance();
+ if (IsDecimalDigit(c0_)) {
+ token = ScanNumber(true);
+ } else {
+ token = Token::PERIOD;
+ }
+ break;
+
+ case ':':
+ token = Select(Token::COLON);
+ break;
+
+ case ';':
+ token = Select(Token::SEMICOLON);
+ break;
+
+ case ',':
+ token = Select(Token::COMMA);
+ break;
+
+ case '(':
+ token = Select(Token::LPAREN);
+ break;
+
+ case ')':
+ token = Select(Token::RPAREN);
+ break;
+
+ case '[':
+ token = Select(Token::LBRACK);
+ break;
+
+ case ']':
+ token = Select(Token::RBRACK);
+ break;
+
+ case '{':
+ token = Select(Token::LBRACE);
+ break;
+
+ case '}':
+ token = Select(Token::RBRACE);
+ break;
+
+ case '?':
+ token = Select(Token::CONDITIONAL);
+ break;
+
+ case '~':
+ token = Select(Token::BIT_NOT);
+ break;
+
+ default:
+ if (unicode_cache_->IsIdentifierStart(c0_)) {
+ token = ScanIdentifierOrKeyword();
+ } else if (IsDecimalDigit(c0_)) {
+ token = ScanNumber(false);
+ } else if (SkipWhiteSpace()) {
+ token = Token::WHITESPACE;
+ } else if (c0_ < 0) {
+ token = Token::EOS;
+ } else {
+ token = Select(Token::ILLEGAL);
+ }
+ break;
+ }
+
+ // Continue scanning for tokens as long as we're just skipping
+ // whitespace.
+ } while (token == Token::WHITESPACE);
+
+ next_.location.end_pos = source_pos();
+ next_.token = token;
+}
+
+
+void JavaScriptScanner::SeekForward(int pos) {
+ // After this call, we will have the token at the given position as
+ // the "next" token. The "current" token will be invalid.
+ if (pos == next_.location.beg_pos) return;
+ int current_pos = source_pos();
+ ASSERT_EQ(next_.location.end_pos, current_pos);
+ // Positions inside the lookahead token aren't supported.
+ ASSERT(pos >= current_pos);
+ if (pos != current_pos) {
+ source_->SeekForward(pos - source_->pos());
+ Advance();
+ // This function is only called to seek to the location
+ // of the end of a function (at the "}" token). It doesn't matter
+ // whether there was a line terminator in the part we skip.
+ has_line_terminator_before_next_ = false;
+ has_multiline_comment_before_next_ = false;
+ }
+ Scan();
+}
+
+
+void JavaScriptScanner::ScanEscape() {
+ uc32 c = c0_;
+ Advance();
+
+ // Skip escaped newlines.
+ if (unicode_cache_->IsLineTerminator(c)) {
+ // Allow CR+LF newlines in multiline string literals.
+ if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance();
+ // Allow LF+CR newlines in multiline string literals.
+ if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance();
+ return;
+ }
+
+ switch (c) {
+ case '\'': // fall through
+ case '"' : // fall through
+ case '\\': break;
+ case 'b' : c = '\b'; break;
+ case 'f' : c = '\f'; break;
+ case 'n' : c = '\n'; break;
+ case 'r' : c = '\r'; break;
+ case 't' : c = '\t'; break;
+ case 'u' : {
+ c = ScanHexNumber(4);
+ if (c < 0) c = 'u';
+ break;
+ }
+ case 'v' : c = '\v'; break;
+ case 'x' : {
+ c = ScanHexNumber(2);
+ if (c < 0) c = 'x';
+ break;
+ }
+ case '0' : // fall through
+ case '1' : // fall through
+ case '2' : // fall through
+ case '3' : // fall through
+ case '4' : // fall through
+ case '5' : // fall through
+ case '6' : // fall through
+ case '7' : c = ScanOctalEscape(c, 2); break;
+ }
+
+ // According to ECMA-262, 3rd, 7.8.4 (p 18ff) these
+ // should be illegal, but they are commonly handled
+ // as non-escaped characters by JS VMs.
+ AddLiteralChar(c);
+}
+
+
+// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
+// ECMA-262. Other JS VMs support them.
+uc32 JavaScriptScanner::ScanOctalEscape(uc32 c, int length) {
+ uc32 x = c - '0';
+ int i = 0;
+ for (; i < length; i++) {
+ int d = c0_ - '0';
+ if (d < 0 || d > 7) break;
+ int nx = x * 8 + d;
+ if (nx >= 256) break;
+ x = nx;
+ Advance();
+ }
+ // Anything except '\0' is an octal escape sequence, illegal in strict mode.
+ // Remember the position of octal escape sequences so that an error
+ // can be reported later (in strict mode).
+ // We don't report the error immediately, because the octal escape can
+ // occur before the "use strict" directive.
+ if (c != '0' || i > 0) {
+ octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
+ }
+ return x;
+}
+
+
+Token::Value JavaScriptScanner::ScanString() {
+ uc32 quote = c0_;
+ Advance(); // consume quote
+
+ LiteralScope literal(this);
+ while (c0_ != quote && c0_ >= 0
+ && !unicode_cache_->IsLineTerminator(c0_)) {
+ uc32 c = c0_;
+ Advance();
+ if (c == '\\') {
+ if (c0_ < 0) return Token::ILLEGAL;
+ ScanEscape();
+ } else {
+ AddLiteralChar(c);
+ }
+ }
+ if (c0_ != quote) return Token::ILLEGAL;
+ literal.Complete();
+
+ Advance(); // consume quote
+ return Token::STRING;
+}
+
+
+void JavaScriptScanner::ScanDecimalDigits() {
+ while (IsDecimalDigit(c0_))
+ AddLiteralCharAdvance();
+}
+
+
+Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
+ ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
+
+ enum { DECIMAL, HEX, OCTAL } kind = DECIMAL;
+
+ LiteralScope literal(this);
+ if (seen_period) {
+ // we have already seen a decimal point of the float
+ AddLiteralChar('.');
+ ScanDecimalDigits(); // we know we have at least one digit
+
+ } else {
+ // if the first character is '0' we must check for octals and hex
+ if (c0_ == '0') {
+ int start_pos = source_pos(); // For reporting octal positions.
+ AddLiteralCharAdvance();
+
+ // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number
+ if (c0_ == 'x' || c0_ == 'X') {
+ // hex number
+ kind = HEX;
+ AddLiteralCharAdvance();
+ if (!IsHexDigit(c0_)) {
+ // we must have at least one hex digit after 'x'/'X'
+ return Token::ILLEGAL;
+ }
+ while (IsHexDigit(c0_)) {
+ AddLiteralCharAdvance();
+ }
+ } else if ('0' <= c0_ && c0_ <= '7') {
+ // (possible) octal number
+ kind = OCTAL;
+ while (true) {
+ if (c0_ == '8' || c0_ == '9') {
+ kind = DECIMAL;
+ break;
+ }
+ if (c0_ < '0' || '7' < c0_) {
+ // Octal literal finished.
+ octal_pos_ = Location(start_pos, source_pos());
+ break;
+ }
+ AddLiteralCharAdvance();
+ }
+ }
+ }
+
+ // Parse decimal digits and allow trailing fractional part.
+ if (kind == DECIMAL) {
+ ScanDecimalDigits(); // optional
+ if (c0_ == '.') {
+ AddLiteralCharAdvance();
+ ScanDecimalDigits(); // optional
+ }
+ }
+ }
+
+ // scan exponent, if any
+ if (c0_ == 'e' || c0_ == 'E') {
+ ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
+ if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed
+ // scan exponent
+ AddLiteralCharAdvance();
+ if (c0_ == '+' || c0_ == '-')
+ AddLiteralCharAdvance();
+ if (!IsDecimalDigit(c0_)) {
+ // we must have at least one decimal digit after 'e'/'E'
+ return Token::ILLEGAL;
+ }
+ ScanDecimalDigits();
+ }
+
+ // The source character immediately following a numeric literal must
+ // not be an identifier start or a decimal digit; see ECMA-262
+ // section 7.8.3, page 17 (note that we read only one decimal digit
+ // if the value is 0).
+ if (IsDecimalDigit(c0_) || unicode_cache_->IsIdentifierStart(c0_))
+ return Token::ILLEGAL;
+
+ literal.Complete();
+
+ return Token::NUMBER;
+}
+
+
+uc32 JavaScriptScanner::ScanIdentifierUnicodeEscape() {
+ Advance();
+ if (c0_ != 'u') return -1;
+ Advance();
+ uc32 result = ScanHexNumber(4);
+ if (result < 0) PushBack('u');
+ return result;
+}
+
+
+// ----------------------------------------------------------------------------
+// Keyword Matcher
+
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('b') \
+ KEYWORD("break", Token::BREAK) \
+ KEYWORD_GROUP('c') \
+ KEYWORD("case", Token::CASE) \
+ KEYWORD("catch", Token::CATCH) \
+ KEYWORD("class", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("const", Token::CONST) \
+ KEYWORD("continue", Token::CONTINUE) \
+ KEYWORD_GROUP('d') \
+ KEYWORD("debugger", Token::DEBUGGER) \
+ KEYWORD("default", Token::DEFAULT) \
+ KEYWORD("delete", Token::DELETE) \
+ KEYWORD("do", Token::DO) \
+ KEYWORD_GROUP('e') \
+ KEYWORD("else", Token::ELSE) \
+ KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("export", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD_GROUP('f') \
+ KEYWORD("false", Token::FALSE_LITERAL) \
+ KEYWORD("finally", Token::FINALLY) \
+ KEYWORD("for", Token::FOR) \
+ KEYWORD("function", Token::FUNCTION) \
+ KEYWORD_GROUP('i') \
+ KEYWORD("if", Token::IF) \
+ KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("import", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("in", Token::IN) \
+ KEYWORD("instanceof", Token::INSTANCEOF) \
+ KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('l') \
+ KEYWORD("let", harmony_block_scoping \
+ ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('n') \
+ KEYWORD("new", Token::NEW) \
+ KEYWORD("null", Token::NULL_LITERAL) \
+ KEYWORD_GROUP('p') \
+ KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('r') \
+ KEYWORD("return", Token::RETURN) \
+ KEYWORD_GROUP('s') \
+ KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("super", Token::FUTURE_RESERVED_WORD) \
+ KEYWORD("switch", Token::SWITCH) \
+ KEYWORD_GROUP('t') \
+ KEYWORD("this", Token::THIS) \
+ KEYWORD("throw", Token::THROW) \
+ KEYWORD("true", Token::TRUE_LITERAL) \
+ KEYWORD("try", Token::TRY) \
+ KEYWORD("typeof", Token::TYPEOF) \
+ KEYWORD_GROUP('v') \
+ KEYWORD("var", Token::VAR) \
+ KEYWORD("void", Token::VOID) \
+ KEYWORD_GROUP('w') \
+ KEYWORD("while", Token::WHILE) \
+ KEYWORD("with", Token::WITH) \
+ KEYWORD_GROUP('y') \
+ KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD)
+
+
+static Token::Value KeywordOrIdentifierToken(const char* input,
+ int input_length,
+ bool harmony_block_scoping) {
+ ASSERT(input_length >= 1);
+ const int kMinLength = 2;
+ const int kMaxLength = 10;
+ if (input_length < kMinLength || input_length > kMaxLength) {
+ return Token::IDENTIFIER;
+ }
+ switch (input[0]) {
+ default:
+#define KEYWORD_GROUP_CASE(ch) \
+ break; \
+ case ch:
+#define KEYWORD(keyword, token) \
+ { \
+ /* 'keyword' is a char array, so sizeof(keyword) is */ \
+ /* strlen(keyword) plus 1 for the NUL char. */ \
+ const int keyword_length = sizeof(keyword) - 1; \
+ STATIC_ASSERT(keyword_length >= kMinLength); \
+ STATIC_ASSERT(keyword_length <= kMaxLength); \
+ if (input_length == keyword_length && \
+ input[1] == keyword[1] && \
+ (keyword_length <= 2 || input[2] == keyword[2]) && \
+ (keyword_length <= 3 || input[3] == keyword[3]) && \
+ (keyword_length <= 4 || input[4] == keyword[4]) && \
+ (keyword_length <= 5 || input[5] == keyword[5]) && \
+ (keyword_length <= 6 || input[6] == keyword[6]) && \
+ (keyword_length <= 7 || input[7] == keyword[7]) && \
+ (keyword_length <= 8 || input[8] == keyword[8]) && \
+ (keyword_length <= 9 || input[9] == keyword[9])) { \
+ return token; \
+ } \
+ }
+ KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
+ }
+ return Token::IDENTIFIER;
+}
+
+
+Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
+ ASSERT(unicode_cache_->IsIdentifierStart(c0_));
+ LiteralScope literal(this);
+ // Scan identifier start character.
+ if (c0_ == '\\') {
+ uc32 c = ScanIdentifierUnicodeEscape();
+ // Only allow legal identifier start characters.
+ if (c < 0 ||
+ c == '\\' || // No recursive escapes.
+ !unicode_cache_->IsIdentifierStart(c)) {
+ return Token::ILLEGAL;
+ }
+ AddLiteralChar(c);
+ return ScanIdentifierSuffix(&literal);
+ }
+
+ uc32 first_char = c0_;
+ Advance();
+ AddLiteralChar(first_char);
+
+ // Scan the rest of the identifier characters.
+ while (unicode_cache_->IsIdentifierPart(c0_)) {
+ if (c0_ != '\\') {
+ uc32 next_char = c0_;
+ Advance();
+ AddLiteralChar(next_char);
+ continue;
+ }
+ // Fallthrough if no longer able to complete keyword.
+ return ScanIdentifierSuffix(&literal);
+ }
+
+ literal.Complete();
+
+ if (next_.literal_chars->is_ascii()) {
+ Vector<const char> chars = next_.literal_chars->ascii_literal();
+ return KeywordOrIdentifierToken(chars.start(),
+ chars.length(),
+ harmony_block_scoping_);
+ }
+
+ return Token::IDENTIFIER;
+}
+
+
+Token::Value JavaScriptScanner::ScanIdentifierSuffix(LiteralScope* literal) {
+ // Scan the rest of the identifier characters.
+ while (unicode_cache_->IsIdentifierPart(c0_)) {
+ if (c0_ == '\\') {
+ uc32 c = ScanIdentifierUnicodeEscape();
+ // Only allow legal identifier part characters.
+ if (c < 0 ||
+ c == '\\' ||
+ !unicode_cache_->IsIdentifierPart(c)) {
+ return Token::ILLEGAL;
+ }
+ AddLiteralChar(c);
+ } else {
+ AddLiteralChar(c0_);
+ Advance();
+ }
+ }
+ literal->Complete();
+
+ return Token::IDENTIFIER;
+}
+
+
+bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
+ // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
+ bool in_character_class = false;
+
+ // Previous token is either '/' or '/=', in the second case, the
+ // pattern starts at =.
+ next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
+ next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
+
+ // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
+ // the scanner should pass uninterpreted bodies to the RegExp
+ // constructor.
+ LiteralScope literal(this);
+ if (seen_equal) {
+ AddLiteralChar('=');
+ }
+
+ while (c0_ != '/' || in_character_class) {
+ if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+ if (c0_ == '\\') { // Escape sequence.
+ AddLiteralCharAdvance();
+ if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false;
+ AddLiteralCharAdvance();
+ // If the escape allows more characters, i.e., \x??, \u????, or \c?,
+ // only "safe" characters are allowed (letters, digits, underscore),
+ // otherwise the escape isn't valid and the invalid character has
+ // its normal meaning. I.e., we can just continue scanning without
+ // worrying whether the following characters are part of the escape
+ // or not, since any '/', '\\' or '[' is guaranteed to not be part
+ // of the escape sequence.
+
+ // TODO(896): At some point, parse RegExps more throughly to capture
+ // octal esacpes in strict mode.
+ } else { // Unescaped character.
+ if (c0_ == '[') in_character_class = true;
+ if (c0_ == ']') in_character_class = false;
+ AddLiteralCharAdvance();
+ }
+ }
+ Advance(); // consume '/'
+
+ literal.Complete();
+
+ return true;
+}
+
+
+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() {
+ // Scan regular expression flags.
+ LiteralScope literal(this);
+ while (unicode_cache_->IsIdentifierPart(c0_)) {
+ if (c0_ != '\\') {
+ AddLiteralCharAdvance();
+ } else {
+ if (!ScanLiteralUnicodeEscape()) {
+ break;
+ }
+ }
+ }
+ literal.Complete();
+
+ next_.location.end_pos = source_pos() - 1;
+ return true;
+}
+
} } // namespace v8::internal
diff --git a/src/scanner.h b/src/scanner.h
index e66dd60..16c3a42 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -25,105 +25,538 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Features shared by parsing and pre-parsing scanners.
+
#ifndef V8_SCANNER_H_
#define V8_SCANNER_H_
+#include "allocation.h"
+#include "char-predicates.h"
+#include "checks.h"
+#include "globals.h"
#include "token.h"
-#include "char-predicates-inl.h"
-#include "scanner-base.h"
+#include "unicode-inl.h"
+#include "utils.h"
namespace v8 {
namespace internal {
-// A buffered character stream based on a random access character
-// source (ReadBlock can be called with pos_ pointing to any position,
-// even positions before the current).
-class BufferedUC16CharacterStream: public UC16CharacterStream {
- public:
- BufferedUC16CharacterStream();
- virtual ~BufferedUC16CharacterStream();
+// Returns the value (0 .. 15) of a hexadecimal character c.
+// If c is not a legal hexadecimal character, returns a value < 0.
+inline int HexValue(uc32 c) {
+ c -= '0';
+ if (static_cast<unsigned>(c) <= 9) return c;
+ c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
+ if (static_cast<unsigned>(c) <= 5) return c + 10;
+ return -1;
+}
- virtual void PushBack(uc32 character);
+
+// ---------------------------------------------------------------------
+// Buffered stream of characters, using an internal UC16 buffer.
+
+class UC16CharacterStream {
+ public:
+ UC16CharacterStream() : pos_(0) { }
+ virtual ~UC16CharacterStream() { }
+
+ // Returns and advances past the next UC16 character in the input
+ // stream. If there are no more characters, it returns a negative
+ // value.
+ inline uc32 Advance() {
+ if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
+ pos_++;
+ return static_cast<uc32>(*(buffer_cursor_++));
+ }
+ // Note: currently the following increment is necessary to avoid a
+ // parser problem! The scanner treats the final kEndOfInput as
+ // a character with a position, and does math relative to that
+ // position.
+ pos_++;
+
+ return kEndOfInput;
+ }
+
+ // Return the current position in the character stream.
+ // Starts at zero.
+ inline unsigned pos() const { return pos_; }
+
+ // Skips forward past the next character_count UC16 characters
+ // in the input, or until the end of input if that comes sooner.
+ // Returns the number of characters actually skipped. If less
+ // than character_count,
+ inline unsigned SeekForward(unsigned character_count) {
+ unsigned buffered_chars =
+ static_cast<unsigned>(buffer_end_ - buffer_cursor_);
+ if (character_count <= buffered_chars) {
+ buffer_cursor_ += character_count;
+ pos_ += character_count;
+ return character_count;
+ }
+ return SlowSeekForward(character_count);
+ }
+
+ // Pushes back the most recently read UC16 character (or negative
+ // value if at end of input), i.e., the value returned by the most recent
+ // call to Advance.
+ // Must not be used right after calling SeekForward.
+ virtual void PushBack(int32_t character) = 0;
protected:
- static const unsigned kBufferSize = 512;
- static const unsigned kPushBackStepSize = 16;
+ static const uc32 kEndOfInput = -1;
- virtual unsigned SlowSeekForward(unsigned delta);
- virtual bool ReadBlock();
- virtual void SlowPushBack(uc16 character);
+ // Ensures that the buffer_cursor_ points to the character at
+ // position pos_ of the input, if possible. If the position
+ // is at or after the end of the input, return false. If there
+ // are more characters available, return true.
+ virtual bool ReadBlock() = 0;
+ virtual unsigned SlowSeekForward(unsigned character_count) = 0;
- virtual unsigned BufferSeekForward(unsigned delta) = 0;
- virtual unsigned FillBuffer(unsigned position, unsigned length) = 0;
-
- const uc16* pushback_limit_;
- uc16 buffer_[kBufferSize];
+ const uc16* buffer_cursor_;
+ const uc16* buffer_end_;
+ unsigned pos_;
};
-// Generic string stream.
-class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
+class UnicodeCache {
+// ---------------------------------------------------------------------
+// Caching predicates used by scanners.
public:
- GenericStringUC16CharacterStream(Handle<String> data,
- unsigned start_position,
- unsigned end_position);
- virtual ~GenericStringUC16CharacterStream();
+ UnicodeCache() {}
+ typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
- protected:
- virtual unsigned BufferSeekForward(unsigned delta);
- virtual unsigned FillBuffer(unsigned position, unsigned length);
+ StaticResource<Utf8Decoder>* utf8_decoder() {
+ return &utf8_decoder_;
+ }
- Handle<String> string_;
- unsigned start_position_;
- unsigned length_;
+ bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
+ bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
+ bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
+ bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
+
+ private:
+ unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
+ unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
+ unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
+ unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
+ StaticResource<Utf8Decoder> utf8_decoder_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnicodeCache);
};
-// UC16 stream based on a literal UTF-8 string.
-class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
+// ----------------------------------------------------------------------------
+// LiteralBuffer - Collector of chars of literals.
+
+class LiteralBuffer {
public:
- Utf8ToUC16CharacterStream(const byte* data, unsigned length);
- virtual ~Utf8ToUC16CharacterStream();
+ LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { }
- protected:
- virtual unsigned BufferSeekForward(unsigned delta);
- virtual unsigned FillBuffer(unsigned char_position, unsigned length);
- void SetRawPosition(unsigned char_position);
+ ~LiteralBuffer() {
+ if (backing_store_.length() > 0) {
+ backing_store_.Dispose();
+ }
+ }
- const byte* raw_data_;
- unsigned raw_data_length_; // Measured in bytes, not characters.
- unsigned raw_data_pos_;
- // The character position of the character at raw_data[raw_data_pos_].
- // Not necessarily the same as pos_.
- unsigned raw_character_position_;
+ inline void AddChar(uc16 character) {
+ if (position_ >= backing_store_.length()) ExpandBuffer();
+ if (is_ascii_) {
+ if (character < kMaxAsciiCharCodeU) {
+ backing_store_[position_] = static_cast<byte>(character);
+ position_ += kASCIISize;
+ return;
+ }
+ ConvertToUC16();
+ }
+ *reinterpret_cast<uc16*>(&backing_store_[position_]) = character;
+ position_ += kUC16Size;
+ }
+
+ bool is_ascii() { return is_ascii_; }
+
+ Vector<const uc16> uc16_literal() {
+ ASSERT(!is_ascii_);
+ ASSERT((position_ & 0x1) == 0);
+ return Vector<const uc16>(
+ reinterpret_cast<const uc16*>(backing_store_.start()),
+ position_ >> 1);
+ }
+
+ Vector<const char> ascii_literal() {
+ ASSERT(is_ascii_);
+ return Vector<const char>(
+ reinterpret_cast<const char*>(backing_store_.start()),
+ position_);
+ }
+
+ int length() {
+ return is_ascii_ ? position_ : (position_ >> 1);
+ }
+
+ void Reset() {
+ position_ = 0;
+ is_ascii_ = true;
+ }
+
+ private:
+ static const int kInitialCapacity = 16;
+ static const int kGrowthFactory = 4;
+ static const int kMinConversionSlack = 256;
+ static const int kMaxGrowth = 1 * MB;
+ inline int NewCapacity(int min_capacity) {
+ int capacity = Max(min_capacity, backing_store_.length());
+ int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
+ return new_capacity;
+ }
+
+ void ExpandBuffer() {
+ Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
+ memcpy(new_store.start(), backing_store_.start(), position_);
+ backing_store_.Dispose();
+ backing_store_ = new_store;
+ }
+
+ void ConvertToUC16() {
+ ASSERT(is_ascii_);
+ Vector<byte> new_store;
+ int new_content_size = position_ * kUC16Size;
+ if (new_content_size >= backing_store_.length()) {
+ // Ensure room for all currently read characters as UC16 as well
+ // as the character about to be stored.
+ new_store = Vector<byte>::New(NewCapacity(new_content_size));
+ } else {
+ new_store = backing_store_;
+ }
+ char* src = reinterpret_cast<char*>(backing_store_.start());
+ uc16* dst = reinterpret_cast<uc16*>(new_store.start());
+ for (int i = position_ - 1; i >= 0; i--) {
+ dst[i] = src[i];
+ }
+ if (new_store.start() != backing_store_.start()) {
+ backing_store_.Dispose();
+ backing_store_ = new_store;
+ }
+ position_ = new_content_size;
+ is_ascii_ = false;
+ }
+
+ bool is_ascii_;
+ int position_;
+ Vector<byte> backing_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
};
-// UTF16 buffer to read characters from an external string.
-class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
- public:
- ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
- int start_position,
- int end_position);
- virtual ~ExternalTwoByteStringUC16CharacterStream();
+// ----------------------------------------------------------------------------
+// Scanner base-class.
- virtual void PushBack(uc32 character) {
- ASSERT(buffer_cursor_ > raw_data_);
- buffer_cursor_--;
- pos_--;
+// Generic functionality used by both JSON and JavaScript scanners.
+class Scanner {
+ public:
+ // -1 is outside of the range of any real source code.
+ static const int kNoOctalLocation = -1;
+
+ typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
+
+ class LiteralScope {
+ public:
+ explicit LiteralScope(Scanner* self);
+ ~LiteralScope();
+ void Complete();
+
+ private:
+ Scanner* scanner_;
+ bool complete_;
+ };
+
+ explicit Scanner(UnicodeCache* scanner_contants);
+
+ // Returns the current token again.
+ Token::Value current_token() { return current_.token; }
+
+ // One token look-ahead (past the token returned by Next()).
+ Token::Value peek() const { return next_.token; }
+
+ struct Location {
+ Location(int b, int e) : beg_pos(b), end_pos(e) { }
+ Location() : beg_pos(0), end_pos(0) { }
+
+ bool IsValid() const {
+ return beg_pos >= 0 && end_pos >= beg_pos;
+ }
+
+ static Location invalid() { return Location(-1, -1); }
+
+ int beg_pos;
+ int end_pos;
+ };
+
+ // Returns the location information for the current token
+ // (the token returned by Next()).
+ Location location() const { return current_.location; }
+ Location peek_location() const { return next_.location; }
+
+ // Returns the literal string, if any, for the current token (the
+ // token returned by Next()). The string is 0-terminated and in
+ // UTF-8 format; they may contain 0-characters. Literal strings are
+ // collected for identifiers, strings, and numbers.
+ // These functions only give the correct result if the literal
+ // was scanned between calls to StartLiteral() and TerminateLiteral().
+ bool is_literal_ascii() {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->is_ascii();
}
+ Vector<const char> literal_ascii_string() {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->ascii_literal();
+ }
+ Vector<const uc16> literal_uc16_string() {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->uc16_literal();
+ }
+ int literal_length() const {
+ ASSERT_NOT_NULL(current_.literal_chars);
+ return current_.literal_chars->length();
+ }
+
+ bool literal_contains_escapes() const {
+ Location location = current_.location;
+ int source_length = (location.end_pos - location.beg_pos);
+ if (current_.token == Token::STRING) {
+ // Subtract delimiters.
+ source_length -= 2;
+ }
+ return current_.literal_chars->length() != source_length;
+ }
+
+ // Returns the literal string for the next token (the token that
+ // would be returned if Next() were called).
+ bool is_next_literal_ascii() {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->is_ascii();
+ }
+ Vector<const char> next_literal_ascii_string() {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->ascii_literal();
+ }
+ Vector<const uc16> next_literal_uc16_string() {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->uc16_literal();
+ }
+ int next_literal_length() const {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ return next_.literal_chars->length();
+ }
+
+ UnicodeCache* unicode_cache() { return unicode_cache_; }
+
+ static const int kCharacterLookaheadBufferSize = 1;
protected:
- virtual unsigned SlowSeekForward(unsigned delta) {
- // Fast case always handles seeking.
- return 0;
+ // The current and look-ahead token.
+ struct TokenDesc {
+ Token::Value token;
+ Location location;
+ LiteralBuffer* literal_chars;
+ };
+
+ // Call this after setting source_ to the input.
+ void Init() {
+ // Set c0_ (one character ahead)
+ STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
+ Advance();
+ // Initialize current_ to not refer to a literal.
+ current_.literal_chars = NULL;
}
- virtual bool ReadBlock() {
- // Entire string is read at start.
- return false;
+
+ // Literal buffer support
+ inline void StartLiteral() {
+ LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ?
+ &literal_buffer2_ : &literal_buffer1_;
+ free_buffer->Reset();
+ next_.literal_chars = free_buffer;
}
- Handle<ExternalTwoByteString> source_;
- const uc16* raw_data_; // Pointer to the actual array of characters.
+
+ inline void AddLiteralChar(uc32 c) {
+ ASSERT_NOT_NULL(next_.literal_chars);
+ next_.literal_chars->AddChar(c);
+ }
+
+ // Complete scanning of a literal.
+ inline void TerminateLiteral() {
+ // Does nothing in the current implementation.
+ }
+
+ // Stops scanning of a literal and drop the collected characters,
+ // e.g., due to an encountered error.
+ inline void DropLiteral() {
+ next_.literal_chars = NULL;
+ }
+
+ inline void AddLiteralCharAdvance() {
+ AddLiteralChar(c0_);
+ Advance();
+ }
+
+ // Low-level scanning support.
+ void Advance() { c0_ = source_->Advance(); }
+ void PushBack(uc32 ch) {
+ source_->PushBack(c0_);
+ c0_ = ch;
+ }
+
+ inline Token::Value Select(Token::Value tok) {
+ Advance();
+ return tok;
+ }
+
+ inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
+ Advance();
+ if (c0_ == next) {
+ Advance();
+ return then;
+ } else {
+ return else_;
+ }
+ }
+
+ uc32 ScanHexNumber(int expected_length);
+
+ // Return the current source position.
+ int source_pos() {
+ return source_->pos() - kCharacterLookaheadBufferSize;
+ }
+
+ UnicodeCache* unicode_cache_;
+
+ // Buffers collecting literal strings, numbers, etc.
+ LiteralBuffer literal_buffer1_;
+ LiteralBuffer literal_buffer2_;
+
+ TokenDesc current_; // desc for current token (as returned by Next())
+ TokenDesc next_; // desc for next token (one token look-ahead)
+
+ // Input stream. Must be initialized to an UC16CharacterStream.
+ UC16CharacterStream* source_;
+
+ // One Unicode character look-ahead; c0_ < 0 at the end of the input.
+ uc32 c0_;
+};
+
+// ----------------------------------------------------------------------------
+// JavaScriptScanner - base logic for JavaScript scanning.
+
+class JavaScriptScanner : public Scanner {
+ public:
+ // A LiteralScope that disables recording of some types of JavaScript
+ // literals. If the scanner is configured to not record the specific
+ // type of literal, the scope will not call StartLiteral.
+ class LiteralScope {
+ public:
+ explicit LiteralScope(JavaScriptScanner* self)
+ : scanner_(self), complete_(false) {
+ scanner_->StartLiteral();
+ }
+ ~LiteralScope() {
+ if (!complete_) scanner_->DropLiteral();
+ }
+ void Complete() {
+ scanner_->TerminateLiteral();
+ complete_ = true;
+ }
+
+ private:
+ JavaScriptScanner* scanner_;
+ bool complete_;
+ };
+
+ explicit JavaScriptScanner(UnicodeCache* scanner_contants);
+
+ void Initialize(UC16CharacterStream* source);
+
+ // Returns the next token.
+ Token::Value Next();
+
+ // Returns true if there was a line terminator before the peek'ed token,
+ // possibly inside a multi-line comment.
+ bool HasAnyLineTerminatorBeforeNext() const {
+ return has_line_terminator_before_next_ ||
+ has_multiline_comment_before_next_;
+ }
+
+ // Scans the input as a regular expression pattern, previous
+ // character(s) must be /(=). Returns true if a pattern is scanned.
+ bool ScanRegExpPattern(bool seen_equal);
+ // Returns true if regexp flags are scanned (always since flags can
+ // be empty).
+ bool ScanRegExpFlags();
+
+ // Tells whether the buffer contains an identifier (no escapes).
+ // Used for checking if a property name is an identifier.
+ static bool IsIdentifier(unibrow::CharacterStream* buffer);
+
+ // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
+ uc32 ScanOctalEscape(uc32 c, int length);
+
+ // Returns the location of the last seen octal literal
+ Location octal_position() const { return octal_pos_; }
+ void clear_octal_position() { octal_pos_ = Location::invalid(); }
+
+ // Seek forward to the given position. This operation does not
+ // work in general, for instance when there are pushed back
+ // characters, but works for seeking forward until simple delimiter
+ // tokens, which is what it is used for.
+ void SeekForward(int pos);
+
+ bool HarmonyBlockScoping() const {
+ return harmony_block_scoping_;
+ }
+ void SetHarmonyBlockScoping(bool block_scoping) {
+ harmony_block_scoping_ = block_scoping;
+ }
+
+
+ protected:
+ bool SkipWhiteSpace();
+ Token::Value SkipSingleLineComment();
+ Token::Value SkipMultiLineComment();
+
+ // Scans a single JavaScript token.
+ void Scan();
+
+ void ScanDecimalDigits();
+ Token::Value ScanNumber(bool seen_period);
+ Token::Value ScanIdentifierOrKeyword();
+ Token::Value ScanIdentifierSuffix(LiteralScope* literal);
+
+ void ScanEscape();
+ Token::Value ScanString();
+
+ // Scans a possible HTML comment -- begins with '<!'.
+ Token::Value ScanHtmlComment();
+
+ // Decodes a unicode escape-sequence which is part of an identifier.
+ // If the escape sequence cannot be decoded the result is kBadChar.
+ uc32 ScanIdentifierUnicodeEscape();
+ // Recognizes a uniocde escape-sequence and adds its characters,
+ // uninterpreted, to the current literal. Used for parsing RegExp
+ // flags.
+ bool ScanLiteralUnicodeEscape();
+
+ // Start position of the octal literal last scanned.
+ Location octal_pos_;
+
+ // Whether there is a line terminator whitespace character after
+ // the current token, and before the next. Does not count newlines
+ // inside multiline comments.
+ bool has_line_terminator_before_next_;
+ // Whether there is a multi-line comment that contains a
+ // line-terminator after the current token, and before the next.
+ bool has_multiline_comment_before_next_;
+ // Whether we scan 'let' as a keyword for harmony block scoped
+ // let bindings.
+ bool harmony_block_scoping_;
};
} } // namespace v8::internal
diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc
index 0eacc83..ad31ca4 100644
--- a/src/scopeinfo.cc
+++ b/src/scopeinfo.cc
@@ -39,12 +39,8 @@
static int CompareLocal(Variable* const* v, Variable* const* w) {
- Slot* s = (*v)->AsSlot();
- Slot* t = (*w)->AsSlot();
- // We may have rewritten parameters (that are in the arguments object)
- // and which may have a NULL slot... - find a better solution...
- int x = (s != NULL ? s->index() : 0);
- int y = (t != NULL ? t->index() : 0);
+ int x = (*v)->index();
+ int y = (*w)->index();
// Consider sorting them according to type as well?
return x - y;
}
@@ -86,27 +82,24 @@
for (int i = 0; i < locals.length(); i++) {
Variable* var = locals[i];
if (var->is_used()) {
- Slot* slot = var->AsSlot();
- if (slot != NULL) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- // explicitly added to parameters_ above - ignore
- break;
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ case Variable::PARAMETER:
+ break;
- case Slot::LOCAL:
- ASSERT(stack_slots_.length() == slot->index());
- stack_slots_.Add(var->name());
- break;
+ case Variable::LOCAL:
+ ASSERT(stack_slots_.length() == var->index());
+ stack_slots_.Add(var->name());
+ break;
- case Slot::CONTEXT:
- heap_locals.Add(var);
- break;
+ case Variable::CONTEXT:
+ heap_locals.Add(var);
+ break;
- case Slot::LOOKUP:
- // This is currently not used.
- UNREACHABLE();
- break;
- }
+ case Variable::LOOKUP:
+ // We don't expect lookup variables in the locals list.
+ UNREACHABLE();
+ break;
}
}
}
@@ -115,9 +108,9 @@
if (scope->num_heap_slots() > 0) {
// Add user-defined slots.
for (int i = 0; i < heap_locals.length(); i++) {
- ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS ==
context_slots_.length());
- ASSERT(heap_locals[i]->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(heap_locals[i]->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
context_slots_.Add(heap_locals[i]->name());
context_modes_.Add(heap_locals[i]->mode());
@@ -131,18 +124,18 @@
// For now, this must happen at the very end because of the
// ordering of the scope info slots and the respective slot indices.
if (scope->is_function_scope()) {
- Variable* var = scope->function();
- if (var != NULL &&
- var->is_used() &&
- var->AsSlot()->type() == Slot::CONTEXT) {
- function_name_ = var->name();
+ VariableProxy* proxy = scope->function();
+ if (proxy != NULL &&
+ proxy->var()->is_used() &&
+ proxy->var()->IsContextSlot()) {
+ function_name_ = proxy->name();
// Note that we must not find the function name in the context slot
// list - instead it must be handled separately in the
// Contexts::Lookup() function. Thus record an empty symbol here so we
// get the correct number of context slots.
- ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_slots_.length());
- ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS ==
+ ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length());
context_slots_.Add(FACTORY->empty_symbol());
context_modes_.Add(Variable::INTERNAL);
diff --git a/src/scopeinfo.h b/src/scopeinfo.h
index 1c61f11..40c5c8a 100644
--- a/src/scopeinfo.h
+++ b/src/scopeinfo.h
@@ -156,7 +156,6 @@
static SerializedScopeInfo* Empty();
private:
-
inline Object** ContextEntriesAddr();
inline Object** ParameterEntriesAddr();
@@ -187,6 +186,7 @@
void Clear();
static const int kNotFound = -2;
+
private:
ContextSlotCache() {
for (int i = 0; i < kLength; ++i) {
diff --git a/src/scopes.cc b/src/scopes.cc
index a76492e..d5a7a9f 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -31,7 +31,6 @@
#include "bootstrapper.h"
#include "compiler.h"
-#include "prettyprinter.h"
#include "scopeinfo.h"
#include "allocation-inl.h"
@@ -314,7 +313,7 @@
Variable::VAR,
false,
Variable::THIS);
- var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1));
+ var->AllocateTo(Variable::PARAMETER, -1);
receiver_ = var;
}
@@ -331,6 +330,35 @@
}
+Scope* Scope::FinalizeBlockScope() {
+ ASSERT(is_block_scope());
+ ASSERT(temps_.is_empty());
+ ASSERT(params_.is_empty());
+
+ if (num_var_or_const() > 0) return this;
+
+ // Remove this scope from outer scope.
+ for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) {
+ if (outer_scope_->inner_scopes_[i] == this) {
+ outer_scope_->inner_scopes_.Remove(i);
+ break;
+ }
+ }
+
+ // Reparent inner scopes.
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ outer_scope()->AddInnerScope(inner_scopes_[i]);
+ }
+
+ // Move unresolved variables
+ for (int i = 0; i < unresolved_.length(); i++) {
+ outer_scope()->unresolved_.Add(unresolved_[i]);
+ }
+
+ return NULL;
+}
+
+
Variable* Scope::LocalLookup(Handle<String> name) {
Variable* result = variables_.Lookup(name);
if (result != NULL || scope_info_.is_null()) {
@@ -360,7 +388,7 @@
Variable* var =
variables_.Declare(this, name, mode, true, Variable::NORMAL);
- var->set_rewrite(NewSlot(var, Slot::CONTEXT, index));
+ var->AllocateTo(Variable::CONTEXT, index);
return var;
}
@@ -378,16 +406,18 @@
Variable* Scope::DeclareFunctionVar(Handle<String> name) {
ASSERT(is_function_scope() && function_ == NULL);
- function_ = new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
- return function_;
+ Variable* function_var =
+ new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
+ function_ = new(isolate_->zone()) VariableProxy(isolate_, function_var);
+ return function_var;
}
-void Scope::DeclareParameter(Handle<String> name) {
+void Scope::DeclareParameter(Handle<String> name, Variable::Mode mode) {
ASSERT(!already_resolved());
ASSERT(is_function_scope());
Variable* var =
- variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL);
+ variables_.Declare(this, name, mode, true, Variable::NORMAL);
params_.Add(var);
}
@@ -407,7 +437,8 @@
Variable* Scope::DeclareGlobal(Handle<String> name) {
ASSERT(is_global_scope());
- return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, true,
+ return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL,
+ true,
Variable::NORMAL);
}
@@ -440,8 +471,11 @@
Variable* Scope::NewTemporary(Handle<String> name) {
ASSERT(!already_resolved());
- Variable* var =
- new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL);
+ Variable* var = new Variable(this,
+ name,
+ Variable::TEMPORARY,
+ true,
+ Variable::NORMAL);
temps_.Add(var);
return var;
}
@@ -467,6 +501,28 @@
}
+Declaration* Scope::CheckConflictingVarDeclarations() {
+ int length = decls_.length();
+ for (int i = 0; i < length; i++) {
+ Declaration* decl = decls_[i];
+ if (decl->mode() != Variable::VAR) continue;
+ Handle<String> name = decl->proxy()->name();
+ bool cond = true;
+ for (Scope* scope = decl->scope(); cond ; scope = scope->outer_scope_) {
+ // There is a conflict if there exists a non-VAR binding.
+ Variable* other_var = scope->variables_.Lookup(name);
+ if (other_var != NULL && other_var->mode() != Variable::VAR) {
+ return decl;
+ }
+
+ // Include declaration scope in the iteration but stop after.
+ if (!scope->is_block_scope() && !scope->is_catch_scope()) cond = false;
+ }
+ }
+ return NULL;
+}
+
+
template<class Allocator>
void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
// Collect variables in this scope.
@@ -607,22 +663,40 @@
static void PrintName(Handle<String> name) {
- SmartPointer<char> s = name->ToCString(DISALLOW_NULLS);
+ SmartArrayPointer<char> s = name->ToCString(DISALLOW_NULLS);
PrintF("%s", *s);
}
-static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
- if (var->is_used() || var->rewrite() != NULL) {
+static void PrintLocation(Variable* var) {
+ switch (var->location()) {
+ case Variable::UNALLOCATED:
+ break;
+ case Variable::PARAMETER:
+ PrintF("parameter[%d]", var->index());
+ break;
+ case Variable::LOCAL:
+ PrintF("local[%d]", var->index());
+ break;
+ case Variable::CONTEXT:
+ PrintF("context[%d]", var->index());
+ break;
+ case Variable::LOOKUP:
+ PrintF("lookup");
+ break;
+ }
+}
+
+
+static void PrintVar(int indent, Variable* var) {
+ if (var->is_used() || !var->IsUnallocated()) {
Indent(indent, Variable::Mode2String(var->mode()));
PrintF(" ");
PrintName(var->name());
PrintF("; // ");
- if (var->rewrite() != NULL) {
- PrintF("%s, ", printer->Print(var->rewrite()));
- if (var->is_accessed_from_inner_scope()) PrintF(", ");
- }
+ PrintLocation(var);
if (var->is_accessed_from_inner_scope()) {
+ if (!var->IsUnallocated()) PrintF(", ");
PrintF("inner scope access");
}
PrintF("\n");
@@ -630,10 +704,10 @@
}
-static void PrintMap(PrettyPrinter* printer, int indent, VariableMap* map) {
+static void PrintMap(int indent, VariableMap* map) {
for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
Variable* var = reinterpret_cast<Variable*>(p->value);
- PrintVar(printer, indent, var);
+ PrintVar(indent, var);
}
}
@@ -690,25 +764,24 @@
PrintF("%d heap slots\n", num_heap_slots_); }
// Print locals.
- PrettyPrinter printer;
Indent(n1, "// function var\n");
if (function_ != NULL) {
- PrintVar(&printer, n1, function_);
+ PrintVar(n1, function_->var());
}
Indent(n1, "// temporary vars\n");
for (int i = 0; i < temps_.length(); i++) {
- PrintVar(&printer, n1, temps_[i]);
+ PrintVar(n1, temps_[i]);
}
Indent(n1, "// local vars\n");
- PrintMap(&printer, n1, &variables_);
+ PrintMap(n1, &variables_);
Indent(n1, "// dynamic vars\n");
if (dynamics_ != NULL) {
- PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC));
- PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
- PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
+ PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC));
+ PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
+ PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
}
// Print inner scopes (disable by providing negative n).
@@ -732,7 +805,7 @@
// Declare a new non-local.
var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
// Allocate it by giving it a dynamic lookup.
- var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1));
+ var->AllocateTo(Variable::LOOKUP, -1);
}
return var;
}
@@ -774,7 +847,7 @@
// the name of named function literal is kept in an intermediate scope
// in between this scope and the next outer scope.)
if (function_ != NULL && function_->name().is_identical_to(name)) {
- var = function_;
+ var = function_->var();
} else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive(name, true, invalidated_local);
@@ -989,12 +1062,12 @@
void Scope::AllocateStackSlot(Variable* var) {
- var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++));
+ var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
}
void Scope::AllocateHeapSlot(Variable* var) {
- var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++));
+ var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
}
@@ -1040,14 +1113,14 @@
if (MustAllocate(var)) {
if (MustAllocateInContext(var)) {
- ASSERT(var->rewrite() == NULL || var->IsContextSlot());
- if (var->rewrite() == NULL) {
+ ASSERT(var->IsUnallocated() || var->IsContextSlot());
+ if (var->IsUnallocated()) {
AllocateHeapSlot(var);
}
} else {
- ASSERT(var->rewrite() == NULL || var->IsParameter());
- if (var->rewrite() == NULL) {
- var->set_rewrite(NewSlot(var, Slot::PARAMETER, i));
+ ASSERT(var->IsUnallocated() || var->IsParameter());
+ if (var->IsUnallocated()) {
+ var->AllocateTo(Variable::PARAMETER, i);
}
}
}
@@ -1057,11 +1130,9 @@
void Scope::AllocateNonParameterLocal(Variable* var) {
ASSERT(var->scope() == this);
- ASSERT(var->rewrite() == NULL ||
- !var->IsVariable(isolate_->factory()->result_symbol()) ||
- var->AsSlot() == NULL ||
- var->AsSlot()->type() != Slot::LOCAL);
- if (var->rewrite() == NULL && MustAllocate(var)) {
+ ASSERT(!var->IsVariable(isolate_->factory()->result_symbol()) ||
+ !var->IsStackLocal());
+ if (var->IsUnallocated() && MustAllocate(var)) {
if (MustAllocateInContext(var)) {
AllocateHeapSlot(var);
} else {
@@ -1089,7 +1160,7 @@
// because of the current ScopeInfo implementation (see
// ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
if (function_ != NULL) {
- AllocateNonParameterLocal(function_);
+ AllocateNonParameterLocal(function_->var());
}
}
diff --git a/src/scopes.h b/src/scopes.h
index c2c4179..2917a63 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -112,6 +112,11 @@
void Initialize(bool inside_with);
+ // Checks if the block scope is redundant, i.e. it does not contain any
+ // block scoped declarations. In that case it is removed from the scope
+ // tree and its children are reparented.
+ Scope* FinalizeBlockScope();
+
// ---------------------------------------------------------------------------
// Declarations
@@ -130,7 +135,7 @@
// Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation
// expects all parameters to be declared and from left to right.
- void DeclareParameter(Handle<String> name);
+ void DeclareParameter(Handle<String> name, Variable::Mode mode);
// Declare a local variable in this scope. If the variable has been
// declared before, the previously declared variable is returned.
@@ -182,6 +187,10 @@
// Check if the scope has (at least) one illegal redeclaration.
bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }
+ // For harmony block scoping mode: Check if the scope has conflicting var
+ // declarations, i.e. a var declaration that has been hoisted from a nested
+ // scope over a let binding of the same name.
+ Declaration* CheckConflictingVarDeclarations();
// ---------------------------------------------------------------------------
// Scope-specific info.
@@ -235,7 +244,7 @@
// The variable holding the function literal for named function
// literals, or NULL.
// Only valid for function scopes.
- Variable* function() const {
+ VariableProxy* function() const {
ASSERT(is_function_scope());
return function_;
}
@@ -354,7 +363,7 @@
// Convenience variable.
Variable* receiver_;
// Function variable, if any; function scopes only.
- Variable* function_;
+ VariableProxy* function_;
// Convenience variable; function scopes only.
Variable* arguments_;
@@ -435,10 +444,6 @@
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
- inline Slot* NewSlot(Variable* var, Slot::Type type, int index) {
- return new(isolate_->zone()) Slot(isolate_, var, type, index);
- }
-
void AddInnerScope(Scope* inner_scope) {
if (inner_scope != NULL) {
inner_scopes_.Add(inner_scope);
diff --git a/src/serialize.cc b/src/serialize.cc
index 094ad20..ecb480a 100644
--- a/src/serialize.cc
+++ b/src/serialize.cc
@@ -240,13 +240,14 @@
// Top addresses
const char* AddressNames[] = {
-#define C(name) "Isolate::" #name,
- ISOLATE_ADDRESS_LIST(C)
+#define BUILD_NAME_LITERAL(CamelName, hacker_name) \
+ "Isolate::" #hacker_name "_address",
+ FOR_EACH_ISOLATE_ADDRESS_NAME(BUILD_NAME_LITERAL)
NULL
#undef C
};
- for (uint16_t i = 0; i < Isolate::k_isolate_address_count; ++i) {
+ for (uint16_t i = 0; i < Isolate::kIsolateAddressCount; ++i) {
Add(isolate->get_address_from_id((Isolate::AddressId)i),
TOP_ADDRESS, i, AddressNames[i]);
}
diff --git a/src/smart-pointer.h b/src/smart-array-pointer.h
similarity index 70%
rename from src/smart-pointer.h
rename to src/smart-array-pointer.h
index 0fa8224..00721c1 100644
--- a/src/smart-pointer.h
+++ b/src/smart-array-pointer.h
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -25,8 +25,8 @@
// (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_SMART_POINTER_H_
-#define V8_SMART_POINTER_H_
+#ifndef V8_SMART_ARRAY_POINTER_H_
+#define V8_SMART_ARRAY_POINTER_H_
namespace v8 {
namespace internal {
@@ -35,75 +35,66 @@
// A 'scoped array pointer' that calls DeleteArray on its pointer when the
// destructor is called.
template<typename T>
-class SmartPointer {
+class SmartArrayPointer {
public:
+ // Default constructor. Constructs an empty scoped pointer.
+ inline SmartArrayPointer() : p_(NULL) {}
- // Default constructor. Construct an empty scoped pointer.
- inline SmartPointer() : p(NULL) {}
-
-
- // Construct a scoped pointer from a plain one.
- explicit inline SmartPointer(T* pointer) : p(pointer) {}
-
+ // Constructs a scoped pointer from a plain one.
+ explicit inline SmartArrayPointer(T* ptr) : p_(ptr) {}
// Copy constructor removes the pointer from the original to avoid double
// freeing.
- inline SmartPointer(const SmartPointer<T>& rhs) : p(rhs.p) {
- const_cast<SmartPointer<T>&>(rhs).p = NULL;
+ inline SmartArrayPointer(const SmartArrayPointer<T>& rhs) : p_(rhs.p_) {
+ const_cast<SmartArrayPointer<T>&>(rhs).p_ = NULL;
}
-
// When the destructor of the scoped pointer is executed the plain pointer
// is deleted using DeleteArray. This implies that you must allocate with
// NewArray.
- inline ~SmartPointer() { if (p) DeleteArray(p); }
+ inline ~SmartArrayPointer() { if (p_) DeleteArray(p_); }
+ inline T* operator->() const { return p_; }
// You can get the underlying pointer out with the * operator.
- inline T* operator*() { return p; }
-
+ inline T* operator*() { return p_; }
// You can use [n] to index as if it was a plain pointer
inline T& operator[](size_t i) {
- return p[i];
+ return p_[i];
}
// We don't have implicit conversion to a T* since that hinders migration:
// You would not be able to change a method from returning a T* to
- // returning an SmartPointer<T> and then get errors wherever it is used.
+ // returning an SmartArrayPointer<T> and then get errors wherever it is used.
// If you want to take out the plain pointer and don't want it automatically
// deleted then call Detach(). Afterwards, the smart pointer is empty
// (NULL).
inline T* Detach() {
- T* temp = p;
- p = NULL;
+ T* temp = p_;
+ p_ = NULL;
return temp;
}
-
- // Assignment requires an empty (NULL) SmartPointer as the receiver. Like
+ // Assignment requires an empty (NULL) SmartArrayPointer as the receiver. Like
// the copy constructor it removes the pointer in the original to avoid
// double freeing.
- inline SmartPointer& operator=(const SmartPointer<T>& rhs) {
+ inline SmartArrayPointer& operator=(const SmartArrayPointer<T>& rhs) {
ASSERT(is_empty());
- T* tmp = rhs.p; // swap to handle self-assignment
- const_cast<SmartPointer<T>&>(rhs).p = NULL;
- p = tmp;
+ T* tmp = rhs.p_; // swap to handle self-assignment
+ const_cast<SmartArrayPointer<T>&>(rhs).p_ = NULL;
+ p_ = tmp;
return *this;
}
-
- inline bool is_empty() {
- return p == NULL;
- }
-
+ inline bool is_empty() { return p_ == NULL; }
private:
- T* p;
+ T* p_;
};
} } // namespace v8::internal
-#endif // V8_SMART_POINTER_H_
+#endif // V8_SMART_ARRAY_POINTER_H_
diff --git a/src/spaces.h b/src/spaces.h
index 908cd30..f156496 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1232,8 +1232,8 @@
// Returns the number of total pages in this space.
int CountTotalPages();
#endif
- private:
+ private:
// Returns a pointer to the page of the relocation pointer.
Page* MCRelocationTopPage() { return TopPageOf(mc_forwarding_info_); }
@@ -1816,7 +1816,6 @@
void MarkNodes();
private:
-
Heap* heap_;
// Available bytes on the free list.
diff --git a/src/splay-tree.h b/src/splay-tree.h
index 0cb9ea8..72231e4 100644
--- a/src/splay-tree.h
+++ b/src/splay-tree.h
@@ -123,8 +123,8 @@
Value value() { return value_; }
Node* left() { return left_; }
Node* right() { return right_; }
- private:
+ private:
friend class SplayTree;
friend class Locator;
Key key_;
@@ -143,6 +143,7 @@
Value& value() { return node_->value_; }
void set_value(const Value& value) { node_->value_ = value; }
inline void bind(Node* node) { node_ = node; }
+
private:
Node* node_;
};
@@ -151,7 +152,6 @@
void ForEach(Callback* callback);
protected:
-
// Resets tree root. Existing nodes become unreachable.
void ResetRoot() { root_ = NULL; }
@@ -187,7 +187,6 @@
void Call(Node* node) { delete node; }
private:
-
DISALLOW_COPY_AND_ASSIGN(NodeDeleter);
};
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 9002593..8086cf9 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -252,11 +252,11 @@
}
-SmartPointer<const char> StringStream::ToCString() const {
+SmartArrayPointer<const char> StringStream::ToCString() const {
char* str = NewArray<char>(length_ + 1);
memcpy(str, buffer_, length_);
str[length_] = '\0';
- return SmartPointer<const char>(str);
+ return SmartArrayPointer<const char>(str);
}
diff --git a/src/string-stream.h b/src/string-stream.h
index b3f2e0d..0ba8f52 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -93,6 +93,7 @@
FmtElm(void* value) : type_(POINTER) { // NOLINT
data_.u_pointer_ = value;
}
+
private:
friend class StringStream;
enum Type { INT, DOUBLE, C_STR, LC_STR, OBJ, HANDLE, POINTER };
@@ -142,7 +143,7 @@
void OutputToStdOut() { OutputToFile(stdout); }
void Log();
Handle<String> ToString();
- SmartPointer<const char> ToCString() const;
+ SmartArrayPointer<const char> ToCString() const;
int length() const { return length_; }
// Object printing support.
diff --git a/src/string.js b/src/string.js
index a70eead..297105d 100644
--- a/src/string.js
+++ b/src/string.js
@@ -223,7 +223,7 @@
// Delegate to one of the regular expression variants if necessary.
if (IS_REGEXP(search)) {
%_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
- if (IS_FUNCTION(replace)) {
+ if (IS_SPEC_FUNCTION(replace)) {
if (search.global) {
return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
} else {
@@ -250,7 +250,7 @@
builder.addSpecialSlice(0, start);
// Compute the string to replace with.
- if (IS_FUNCTION(replace)) {
+ if (IS_SPEC_FUNCTION(replace)) {
var receiver = %GetDefaultReceiver(replace);
builder.add(%_CallFunction(receiver,
search,
@@ -440,13 +440,14 @@
i++;
}
} else {
+ var receiver = %GetDefaultReceiver(replace);
while (i < len) {
var elem = res[i];
if (!%_IsSmi(elem)) {
// elem must be an Array.
// Use the apply argument as backing for global RegExp properties.
lastMatchInfoOverride = elem;
- var func_result = replace.apply(null, elem);
+ var func_result = %Apply(replace, receiver, elem, 0, elem.length);
res[i] = TO_STRING_INLINE(func_result);
}
i++;
@@ -472,11 +473,11 @@
// The number of captures plus one for the match.
var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
var replacement;
+ var receiver = %GetDefaultReceiver(replace);
if (m == 1) {
// No captures, only the match, which is always valid.
var s = SubString(subject, index, endOfMatch);
// Don't call directly to avoid exposing the built-in global object.
- var receiver = %GetDefaultReceiver(replace);
replacement =
%_CallFunction(receiver, s, index, subject, replace);
} else {
@@ -487,7 +488,7 @@
parameters[j] = index;
parameters[j + 1] = subject;
- replacement = replace.apply(null, parameters);
+ replacement = %Apply(replace, receiver, parameters, 0, j + 2);
}
result.add(replacement); // The add method converts to string if necessary.
@@ -911,50 +912,47 @@
this.special_string = str;
}
-ReplaceResultBuilder.prototype.__proto__ = null;
-
-
-ReplaceResultBuilder.prototype.add = function(str) {
- str = TO_STRING_INLINE(str);
- if (str.length > 0) this.elements.push(str);
-}
-
-
-ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
- var len = end - start;
- if (start < 0 || len <= 0) return;
- if (start < 0x80000 && len < 0x800) {
- this.elements.push((start << 11) | len);
- } else {
- // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
- // so -len is a smi.
+SetUpLockedPrototype(ReplaceResultBuilder,
+ $Array("elements", "special_string"), $Array(
+ "add", function(str) {
+ str = TO_STRING_INLINE(str);
+ if (str.length > 0) this.elements.push(str);
+ },
+ "addSpecialSlice", function(start, end) {
+ var len = end - start;
+ if (start < 0 || len <= 0) return;
+ if (start < 0x80000 && len < 0x800) {
+ this.elements.push((start << 11) | len);
+ } else {
+ // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
+ // so -len is a smi.
+ var elements = this.elements;
+ elements.push(-len);
+ elements.push(start);
+ }
+ },
+ "generate", function() {
var elements = this.elements;
- elements.push(-len);
- elements.push(start);
+ return %StringBuilderConcat(elements, elements.length, this.special_string);
}
-}
-
-
-ReplaceResultBuilder.prototype.generate = function() {
- var elements = this.elements;
- return %StringBuilderConcat(elements, elements.length, this.special_string);
-}
+));
// -------------------------------------------------------------------
-function SetupString() {
- // Setup the constructor property on the String prototype object.
+function SetUpString() {
+ %CheckIsBootstrapping();
+ // Set up the constructor property on the String prototype object.
%SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
- // Setup the non-enumerable functions on the String object.
+ // Set up the non-enumerable functions on the String object.
InstallFunctions($String, DONT_ENUM, $Array(
"fromCharCode", StringFromCharCode
));
- // Setup the non-enumerable functions on the String prototype object.
+ // Set up the non-enumerable functions on the String prototype object.
InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array(
"valueOf", StringValueOf,
"toString", StringToString,
@@ -994,5 +992,4 @@
));
}
-
-SetupString();
+SetUpString();
diff --git a/src/strtod.cc b/src/strtod.cc
index 568531e..c89c8f3 100644
--- a/src/strtod.cc
+++ b/src/strtod.cc
@@ -27,8 +27,9 @@
#include <stdarg.h>
#include <math.h>
+#include <limits>
-#include "platform.h"
+#include "globals.h"
#include "utils.h"
#include "strtod.h"
#include "bignum.h"
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 13b0b63..5596330 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -74,7 +74,7 @@
// the bits are the least significant so they will be the ones
// masked out.
ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
- ASSERT(Code::kFlagsICStateShift == 0);
+ STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
// Make sure that the code type is not included in the hash.
ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
@@ -652,7 +652,6 @@
(kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
MaybeObject* StubCache::ComputeCallConstant(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -678,7 +677,6 @@
CONSTANT_FUNCTION,
extra_ic_state,
cache_holder,
- in_loop,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
@@ -688,8 +686,7 @@
// caches.
if (!function->is_compiled()) return Failure::InternalError();
// Compile the stub - only create stubs for fully compiled functions.
- CallStubCompiler compiler(
- argc, in_loop, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallConstant(object, holder, function, name, check);
if (!maybe_code->ToObject(&code)) return maybe_code;
@@ -711,7 +708,6 @@
MaybeObject* StubCache::ComputeCallField(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -734,12 +730,10 @@
FIELD,
extra_ic_state,
cache_holder,
- in_loop,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- CallStubCompiler compiler(
- argc, in_loop, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallField(JSObject::cast(object),
holder,
@@ -785,12 +779,10 @@
INTERCEPTOR,
extra_ic_state,
cache_holder,
- NOT_IN_LOOP,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- CallStubCompiler compiler(
- argc, NOT_IN_LOOP, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
@@ -811,14 +803,12 @@
MaybeObject* StubCache::ComputeCallNormal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
JSObject* receiver) {
Object* code;
- { MaybeObject* maybe_code =
- ComputeCallNormal(argc, in_loop, kind, extra_ic_state);
+ { MaybeObject* maybe_code = ComputeCallNormal(argc, kind, extra_ic_state);
if (!maybe_code->ToObject(&code)) return maybe_code;
}
return code;
@@ -826,7 +816,6 @@
MaybeObject* StubCache::ComputeCallGlobal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -841,7 +830,6 @@
NORMAL,
extra_ic_state,
cache_holder,
- in_loop,
argc);
Object* code = map_holder->map()->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
@@ -850,8 +838,7 @@
// internal error which will make sure we do not update any
// caches.
if (!function->is_compiled()) return Failure::InternalError();
- CallStubCompiler compiler(
- argc, in_loop, kind, extra_ic_state, cache_holder);
+ CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
{ MaybeObject* maybe_code =
compiler.CompileCallGlobal(receiver, holder, cell, function, name);
if (!maybe_code->ToObject(&code)) return maybe_code;
@@ -920,14 +907,12 @@
Code* StubCache::FindCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind) {
Code::ExtraICState extra_state =
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
UNINITIALIZED,
extra_state,
NORMAL,
@@ -941,14 +926,12 @@
MaybeObject* StubCache::ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind) {
Code::ExtraICState extra_state =
CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
UNINITIALIZED,
extra_state,
NORMAL,
@@ -964,49 +947,26 @@
Handle<Code> StubCache::ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode) {
- if (in_loop == IN_LOOP) {
- // Force the creation of the corresponding stub outside loops,
- // because it may be used when clearing the ICs later - it is
- // possible for a series of IC transitions to lose the in-loop
- // information, and the IC clearing code can't generate a stub
- // that it needs so we need to ensure it is generated already.
- ComputeCallInitialize(argc, NOT_IN_LOOP, mode);
- }
CALL_HEAP_FUNCTION(isolate_,
- ComputeCallInitialize(argc, in_loop, mode, Code::CALL_IC),
+ ComputeCallInitialize(argc, mode, Code::CALL_IC),
Code);
}
-Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
- InLoopFlag in_loop) {
- if (in_loop == IN_LOOP) {
- // Force the creation of the corresponding stub outside loops,
- // because it may be used when clearing the ICs later - it is
- // possible for a series of IC transitions to lose the in-loop
- // information, and the IC clearing code can't generate a stub
- // that it needs so we need to ensure it is generated already.
- ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
- }
+Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
CALL_HEAP_FUNCTION(
isolate_,
- ComputeCallInitialize(argc,
- in_loop,
- RelocInfo::CODE_TARGET,
- Code::KEYED_CALL_IC),
+ ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, Code::KEYED_CALL_IC),
Code);
}
MaybeObject* StubCache::ComputeCallPreMonomorphic(
int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
PREMONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1022,11 +982,9 @@
MaybeObject* StubCache::ComputeCallNormal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1041,12 +999,9 @@
}
-MaybeObject* StubCache::ComputeCallArguments(int argc,
- InLoopFlag in_loop,
- Code::Kind kind) {
+MaybeObject* StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
ASSERT(kind == Code::KEYED_CALL_IC);
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
MEGAMORPHIC,
Code::kNoExtraICState,
NORMAL,
@@ -1063,11 +1018,9 @@
MaybeObject* StubCache::ComputeCallMegamorphic(
int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
Code::Flags flags = Code::ComputeFlags(kind,
- in_loop,
MEGAMORPHIC,
extra_ic_state,
NORMAL,
@@ -1088,7 +1041,6 @@
// MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
// and monomorphic stubs are not mixed up together in the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC_PROTOTYPE_FAILURE,
extra_ic_state,
NORMAL,
@@ -1111,7 +1063,6 @@
// Extra IC state is irrelevant for debug break ICs. They jump to
// the actual call ic to carry out the work.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
DEBUG_BREAK,
Code::kNoExtraICState,
NORMAL,
@@ -1132,7 +1083,6 @@
// Extra IC state is irrelevant for debug break ICs. They jump to
// the actual call ic to carry out the work.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
DEBUG_PREPARE_STEP_IN,
Code::kNoExtraICState,
NORMAL,
@@ -1672,7 +1622,7 @@
String* name,
InlineCacheState state) {
Code::Flags flags = Code::ComputeFlags(
- Code::KEYED_LOAD_IC, NOT_IN_LOOP, state, Code::kNoExtraICState, type);
+ Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1688,8 +1638,8 @@
MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::STORE_IC, type, strict_mode_);
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1707,8 +1657,8 @@
MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type,
String* name,
InlineCacheState state) {
- Code::Flags flags = Code::ComputeFlags(
- Code::KEYED_STORE_IC, NOT_IN_LOOP, state, strict_mode_, type);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::KEYED_STORE_IC, state, strict_mode_, type);
MaybeObject* result = GetCodeWithFlags(flags, name);
if (!result->IsFailure()) {
PROFILE(isolate(),
@@ -1730,12 +1680,10 @@
CallStubCompiler::CallStubCompiler(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
InlineCacheHolderFlag cache_holder)
: arguments_(argc),
- in_loop_(in_loop),
kind_(kind),
extra_ic_state_(extra_ic_state),
cache_holder_(cache_holder) {
@@ -1796,7 +1744,6 @@
type,
extra_ic_state_,
cache_holder_,
- in_loop_,
argc);
return GetCodeWithFlags(flags, name);
}
diff --git a/src/stub-cache.h b/src/stub-cache.h
index dd06a1c..18c157b 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -194,7 +194,6 @@
MUST_USE_RESULT MaybeObject* ComputeCallField(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -204,7 +203,6 @@
MUST_USE_RESULT MaybeObject* ComputeCallConstant(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -214,7 +212,6 @@
MUST_USE_RESULT MaybeObject* ComputeCallNormal(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -230,7 +227,6 @@
MUST_USE_RESULT MaybeObject* ComputeCallGlobal(
int argc,
- InLoopFlag in_loop,
Code::Kind,
Code::ExtraICState extra_ic_state,
String* name,
@@ -242,33 +238,27 @@
// ---
MUST_USE_RESULT MaybeObject* ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind);
Handle<Code> ComputeCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode);
- Handle<Code> ComputeKeyedCallInitialize(int argc, InLoopFlag in_loop);
+ Handle<Code> ComputeKeyedCallInitialize(int argc);
MUST_USE_RESULT MaybeObject* ComputeCallPreMonomorphic(
int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state);
MUST_USE_RESULT MaybeObject* ComputeCallNormal(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState state);
MUST_USE_RESULT MaybeObject* ComputeCallArguments(int argc,
- InLoopFlag in_loop,
Code::Kind kind);
MUST_USE_RESULT MaybeObject* ComputeCallMegamorphic(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState state);
@@ -278,7 +268,6 @@
// Finds the Code object stored in the Heap::non_monomorphic_cache().
MUST_USE_RESULT Code* FindCallInitialize(int argc,
- InLoopFlag in_loop,
RelocInfo::Mode mode,
Code::Kind kind);
@@ -379,11 +368,7 @@
// Use the seed from the primary cache in the secondary cache.
uint32_t string_low32bits =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
- // We always set the in_loop bit to zero when generating the lookup code
- // so do it here too so the hash codes match.
- uint32_t iflags =
- (static_cast<uint32_t>(flags) & ~Code::kFlagsICInLoopMask);
- uint32_t key = seed - string_low32bits + iflags;
+ uint32_t key = seed - string_low32bits + flags;
return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
}
@@ -660,7 +645,7 @@
CodeList* handler_ics);
static void GenerateLoadExternalArray(MacroAssembler* masm,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
static void GenerateLoadFastElement(MacroAssembler* masm);
@@ -725,7 +710,7 @@
bool is_js_array);
static void GenerateStoreExternalArray(MacroAssembler* masm,
- JSObject::ElementsKind elements_kind);
+ ElementsKind elements_kind);
static void GenerateStoreDictionaryElement(MacroAssembler* masm);
@@ -755,7 +740,6 @@
class CallStubCompiler: public StubCompiler {
public:
CallStubCompiler(int argc,
- InLoopFlag in_loop,
Code::Kind kind,
Code::ExtraICState extra_ic_state,
InlineCacheHolderFlag cache_holder);
@@ -815,7 +799,6 @@
String* name);
const ParameterCount arguments_;
- const InLoopFlag in_loop_;
const Code::Kind kind_;
const Code::ExtraICState extra_ic_state_;
const InlineCacheHolderFlag cache_holder_;
diff --git a/src/type-info.cc b/src/type-info.cc
index bdf7bc3..c64368e 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -190,7 +190,6 @@
NORMAL,
extra_ic_state,
OWN_MAP,
- NOT_IN_LOOP,
arity);
CollectReceiverTypes(expr->id(), name, flags, types);
}
diff --git a/src/uri.js b/src/uri.js
index 72ca6f1..c910d75 100644
--- a/src/uri.js
+++ b/src/uri.js
@@ -392,8 +392,9 @@
// -------------------------------------------------------------------
-function SetupURI() {
- // Setup non-enumerable URI functions on the global object and set
+function SetUpUri() {
+ %CheckIsBootstrapping();
+ // Set up non-enumerable URI functions on the global object and set
// their names.
InstallFunctions(global, DONT_ENUM, $Array(
"escape", URIEscape,
@@ -405,4 +406,4 @@
));
}
-SetupURI();
+SetUpUri();
diff --git a/src/utils.h b/src/utils.h
index 785bc43..26c522b 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -203,16 +203,17 @@
template<class T, int shift, int size>
class BitField {
public:
+ // A uint32_t mask of bit field. To use all bits of a uint32 in a
+ // bitfield without compiler warnings we have to compute 2^32 without
+ // using a shift count of 32.
+ static const uint32_t kMask = ((1U << shift) << size) - (1U << shift);
+
+ // Value for the field with all bits set.
+ static const T kMax = static_cast<T>((1U << size) - 1);
+
// Tells whether the provided value fits into the bit field.
static bool is_valid(T value) {
- return (static_cast<uint32_t>(value) & ~((1U << (size)) - 1)) == 0;
- }
-
- // Returns a uint32_t mask of bit field.
- static uint32_t mask() {
- // To use all bits of a uint32 in a bitfield without compiler warnings we
- // have to compute 2^32 without using a shift count of 32.
- return ((1U << shift) << size) - (1U << shift);
+ return (static_cast<uint32_t>(value) & ~static_cast<uint32_t>(kMax)) == 0;
}
// Returns a uint32_t with the bit field value encoded.
@@ -223,17 +224,12 @@
// Returns a uint32_t with the bit field value updated.
static uint32_t update(uint32_t previous, T value) {
- return (previous & ~mask()) | encode(value);
+ return (previous & ~kMask) | encode(value);
}
// Extracts the bit field from the value.
static T decode(uint32_t value) {
- return static_cast<T>((value & mask()) >> shift);
- }
-
- // Value for the field with all bits set.
- static T max() {
- return decode(mask());
+ return static_cast<T>((value & kMask) >> shift);
}
};
@@ -497,9 +493,6 @@
public:
explicit Collector(int initial_capacity = kMinCapacity)
: index_(0), size_(0) {
- if (initial_capacity < kMinCapacity) {
- initial_capacity = kMinCapacity;
- }
current_chunk_ = Vector<T>::New(initial_capacity);
}
@@ -601,25 +594,23 @@
// Creates a new current chunk, and stores the old chunk in the chunks_ list.
void Grow(int min_capacity) {
ASSERT(growth_factor > 1);
- int growth = current_chunk_.length() * (growth_factor - 1);
- if (growth > max_growth) {
- growth = max_growth;
- }
- int new_capacity = current_chunk_.length() + growth;
- if (new_capacity < min_capacity) {
- new_capacity = min_capacity + growth;
- }
- Vector<T> new_chunk = Vector<T>::New(new_capacity);
- int new_index = PrepareGrow(new_chunk);
- if (index_ > 0) {
- chunks_.Add(current_chunk_.SubVector(0, index_));
+ int new_capacity;
+ int current_length = current_chunk_.length();
+ if (current_length < kMinCapacity) {
+ // The collector started out as empty.
+ new_capacity = min_capacity * growth_factor;
+ if (new_capacity < kMinCapacity) new_capacity = kMinCapacity;
} else {
- // Can happen if the call to PrepareGrow moves everything into
- // the new chunk.
- current_chunk_.Dispose();
+ int growth = current_length * (growth_factor - 1);
+ if (growth > max_growth) {
+ growth = max_growth;
+ }
+ new_capacity = current_length + growth;
+ if (new_capacity < min_capacity) {
+ new_capacity = min_capacity + growth;
+ }
}
- current_chunk_ = new_chunk;
- index_ = new_index;
+ NewChunk(new_capacity);
ASSERT(index_ + min_capacity <= current_chunk_.length());
}
@@ -627,8 +618,15 @@
// some of the current data into the new chunk. The function may update
// the current index_ value to represent data no longer in the current chunk.
// Returns the initial index of the new chunk (after copied data).
- virtual int PrepareGrow(Vector<T> new_chunk) {
- return 0;
+ virtual void NewChunk(int new_capacity) {
+ Vector<T> new_chunk = Vector<T>::New(new_capacity);
+ if (index_ > 0) {
+ chunks_.Add(current_chunk_.SubVector(0, index_));
+ } else {
+ current_chunk_.Dispose();
+ }
+ current_chunk_ = new_chunk;
+ index_ = 0;
}
};
@@ -683,20 +681,26 @@
int sequence_start_;
// Move the currently active sequence to the new chunk.
- virtual int PrepareGrow(Vector<T> new_chunk) {
- if (sequence_start_ != kNoSequence) {
- int sequence_length = this->index_ - sequence_start_;
- // The new chunk is always larger than the current chunk, so there
- // is room for the copy.
- ASSERT(sequence_length < new_chunk.length());
- for (int i = 0; i < sequence_length; i++) {
- new_chunk[i] = this->current_chunk_[sequence_start_ + i];
- }
- this->index_ = sequence_start_;
- sequence_start_ = 0;
- return sequence_length;
+ virtual void NewChunk(int new_capacity) {
+ if (sequence_start_ == kNoSequence) {
+ // Fall back on default behavior if no sequence has been started.
+ this->Collector<T, growth_factor, max_growth>::NewChunk(new_capacity);
+ return;
}
- return 0;
+ int sequence_length = this->index_ - sequence_start_;
+ Vector<T> new_chunk = Vector<T>::New(sequence_length + new_capacity);
+ ASSERT(sequence_length < new_chunk.length());
+ for (int i = 0; i < sequence_length; i++) {
+ new_chunk[i] = this->current_chunk_[sequence_start_ + i];
+ }
+ if (sequence_start_ > 0) {
+ this->chunks_.Add(this->current_chunk_.SubVector(0, sequence_start_));
+ } else {
+ this->current_chunk_.Dispose();
+ }
+ this->current_chunk_ = new_chunk;
+ this->index_ = sequence_length;
+ sequence_start_ = 0;
}
};
@@ -882,6 +886,7 @@
int position_;
bool is_finalized() const { return position_ < 0; }
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SimpleStringBuilder);
};
diff --git a/src/v8conversions.cc b/src/v8conversions.cc
index 96056ec..bf175e5 100644
--- a/src/v8conversions.cc
+++ b/src/v8conversions.cc
@@ -34,7 +34,6 @@
#include "v8conversions.h"
#include "dtoa.h"
#include "factory.h"
-#include "scanner-base.h"
#include "strtod.h"
namespace v8 {
diff --git a/src/v8globals.h b/src/v8globals.h
index f05a702..eb5c49d 100644
--- a/src/v8globals.h
+++ b/src/v8globals.h
@@ -98,6 +98,10 @@
const int kProcessorCacheLineSize = 64;
// Constants relevant to double precision floating point numbers.
+
+// Quiet NaNs have bits 51 to 62 set, possibly the sign bit, and no
+// other bits set.
+const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
// If looking only at the top 32 bits, the QNaN mask is bits 19 to 30.
const uint32_t kQuietNaNHighBitsMask = 0xfff << (51 - 32);
@@ -298,12 +302,6 @@
};
-enum InLoopFlag {
- NOT_IN_LOOP,
- IN_LOOP
-};
-
-
enum CallFunctionFlags {
NO_CALL_FUNCTION_FLAGS = 0,
// Receiver might implicitly be the global objects. If it is, the
@@ -330,7 +328,7 @@
HANDLER = 4, // only in lookup results, not in descriptors
INTERCEPTOR = 5, // only in lookup results, not in descriptors
MAP_TRANSITION = 6, // only in fast mode
- EXTERNAL_ARRAY_TRANSITION = 7,
+ ELEMENTS_TRANSITION = 7,
CONSTANT_TRANSITION = 8, // only in fast mode
NULL_DESCRIPTOR = 9, // only in fast mode
// All properties before MAP_TRANSITION are real.
diff --git a/src/v8natives.js b/src/v8natives.js
index 982e18e..588bdb2 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -41,7 +41,6 @@
const $isNaN = GlobalIsNaN;
const $isFinite = GlobalIsFinite;
-
// ----------------------------------------------------------------------------
@@ -66,28 +65,56 @@
// functions on String.prototype etc. and then restore the old function
// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
+ %CheckIsBootstrapping();
var hidden_prototype = new $Object();
%SetHiddenPrototype(object, hidden_prototype);
InstallFunctions(hidden_prototype, attributes, functions);
}
+// Prevents changes to the prototype of a built-infunction.
+// The "prototype" property of the function object is made non-configurable,
+// and the prototype object is made non-extensible. The latter prevents
+// changing the __proto__ property.
+function SetUpLockedPrototype(constructor, fields, methods) {
+ %CheckIsBootstrapping();
+ var prototype = constructor.prototype;
+ // Install functions first, because this function is used to initialize
+ // PropertyDescriptor itself.
+ var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
+ if (property_count >= 4) {
+ %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
+ }
+ if (fields) {
+ for (var i = 0; i < fields.length; i++) {
+ %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
+ }
+ }
+ for (var i = 0; i < methods.length; i += 2) {
+ var key = methods[i];
+ var f = methods[i + 1];
+ %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetNativeFlag(f);
+ }
+ prototype.__proto__ = null;
+ %ToFastProperties(prototype);
+}
+
+
// ----------------------------------------------------------------------------
// ECMA 262 - 15.1.4
function GlobalIsNaN(number) {
- var n = ToNumber(number);
- return NUMBER_IS_NAN(n);
+ if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
+ return NUMBER_IS_NAN(number);
}
// ECMA 262 - 15.1.5
function GlobalIsFinite(number) {
if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
-
- // NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN.
- return %_IsSmi(number) || number - number == 0;
+ return NUMBER_IS_FINITE(number);
}
@@ -162,8 +189,9 @@
// ----------------------------------------------------------------------------
-
-function SetupGlobal() {
+// Set up global object.
+function SetUpGlobal() {
+ %CheckIsBootstrapping();
// ECMA 262 - 15.1.1.1.
%SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
@@ -173,7 +201,7 @@
// ECMA-262 - 15.1.1.3.
%SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
- // Setup non-enumerable function on the global object.
+ // Set up non-enumerable function on the global object.
InstallFunctions(global, DONT_ENUM, $Array(
"isNaN", GlobalIsNaN,
"isFinite", GlobalIsFinite,
@@ -183,8 +211,7 @@
));
}
-SetupGlobal();
-
+SetUpGlobal();
// ----------------------------------------------------------------------------
// Boolean (first part of definition)
@@ -271,7 +298,7 @@
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
receiver = %GlobalReceiver(global);
}
- if (!IS_FUNCTION(fun)) {
+ if (!IS_SPEC_FUNCTION(fun)) {
throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
}
var desc = new PropertyDescriptor();
@@ -296,7 +323,7 @@
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
receiver = %GlobalReceiver(global);
}
- if (!IS_FUNCTION(fun)) {
+ if (!IS_SPEC_FUNCTION(fun)) {
throw new $TypeError(
'Object.prototype.__defineSetter__: Expecting function');
}
@@ -426,7 +453,7 @@
if ("get" in obj) {
var get = obj.get;
- if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
+ if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
throw MakeTypeError("getter_must_be_callable", [get]);
}
desc.setGet(get);
@@ -434,7 +461,7 @@
if ("set" in obj) {
var set = obj.set;
- if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
+ if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
throw MakeTypeError("setter_must_be_callable", [set]);
}
desc.setSet(set);
@@ -481,106 +508,83 @@
this.hasSetter_ = false;
}
-PropertyDescriptor.prototype.__proto__ = null;
-
-PropertyDescriptor.prototype.toString = function() {
- return "[object PropertyDescriptor]";
-};
-
-PropertyDescriptor.prototype.setValue = function(value) {
- this.value_ = value;
- this.hasValue_ = true;
-}
-
-
-PropertyDescriptor.prototype.getValue = function() {
- return this.value_;
-}
-
-
-PropertyDescriptor.prototype.hasValue = function() {
- return this.hasValue_;
-}
-
-
-PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
- this.enumerable_ = enumerable;
- this.hasEnumerable_ = true;
-}
-
-
-PropertyDescriptor.prototype.isEnumerable = function () {
- return this.enumerable_;
-}
-
-
-PropertyDescriptor.prototype.hasEnumerable = function() {
- return this.hasEnumerable_;
-}
-
-
-PropertyDescriptor.prototype.setWritable = function(writable) {
- this.writable_ = writable;
- this.hasWritable_ = true;
-}
-
-
-PropertyDescriptor.prototype.isWritable = function() {
- return this.writable_;
-}
-
-
-PropertyDescriptor.prototype.hasWritable = function() {
- return this.hasWritable_;
-}
-
-
-PropertyDescriptor.prototype.setConfigurable = function(configurable) {
- this.configurable_ = configurable;
- this.hasConfigurable_ = true;
-}
-
-
-PropertyDescriptor.prototype.hasConfigurable = function() {
- return this.hasConfigurable_;
-}
-
-
-PropertyDescriptor.prototype.isConfigurable = function() {
- return this.configurable_;
-}
-
-
-PropertyDescriptor.prototype.setGet = function(get) {
- this.get_ = get;
- this.hasGetter_ = true;
-}
-
-
-PropertyDescriptor.prototype.getGet = function() {
- return this.get_;
-}
-
-
-PropertyDescriptor.prototype.hasGetter = function() {
- return this.hasGetter_;
-}
-
-
-PropertyDescriptor.prototype.setSet = function(set) {
- this.set_ = set;
- this.hasSetter_ = true;
-}
-
-
-PropertyDescriptor.prototype.getSet = function() {
- return this.set_;
-}
-
-
-PropertyDescriptor.prototype.hasSetter = function() {
- return this.hasSetter_;
-}
+SetUpLockedPrototype(PropertyDescriptor, $Array(
+ "value_",
+ "hasValue_",
+ "writable_",
+ "hasWritable_",
+ "enumerable_",
+ "hasEnumerable_",
+ "configurable_",
+ "hasConfigurable_",
+ "get_",
+ "hasGetter_",
+ "set_",
+ "hasSetter_"
+ ), $Array(
+ "toString", function() {
+ return "[object PropertyDescriptor]";
+ },
+ "setValue", function(value) {
+ this.value_ = value;
+ this.hasValue_ = true;
+ },
+ "getValue", function() {
+ return this.value_;
+ },
+ "hasValue", function() {
+ return this.hasValue_;
+ },
+ "setEnumerable", function(enumerable) {
+ this.enumerable_ = enumerable;
+ this.hasEnumerable_ = true;
+ },
+ "isEnumerable", function () {
+ return this.enumerable_;
+ },
+ "hasEnumerable", function() {
+ return this.hasEnumerable_;
+ },
+ "setWritable", function(writable) {
+ this.writable_ = writable;
+ this.hasWritable_ = true;
+ },
+ "isWritable", function() {
+ return this.writable_;
+ },
+ "hasWritable", function() {
+ return this.hasWritable_;
+ },
+ "setConfigurable", function(configurable) {
+ this.configurable_ = configurable;
+ this.hasConfigurable_ = true;
+ },
+ "hasConfigurable", function() {
+ return this.hasConfigurable_;
+ },
+ "isConfigurable", function() {
+ return this.configurable_;
+ },
+ "setGet", function(get) {
+ this.get_ = get;
+ this.hasGetter_ = true;
+ },
+ "getGet", function() {
+ return this.get_;
+ },
+ "hasGetter", function() {
+ return this.hasGetter_;
+ },
+ "setSet", function(set) {
+ this.set_ = set;
+ this.hasSetter_ = true;
+ },
+ "getSet", function() {
+ return this.set_;
+ },
+ "hasSetter", function() {
+ return this.hasSetter_;
+ }));
// Converts an array returned from Runtime_GetOwnProperty to an actual
@@ -619,7 +623,7 @@
throw MakeTypeError("handler_trap_missing", [handler, name]);
}
trap = defaultTrap;
- } else if (!IS_FUNCTION(trap)) {
+ } else if (!IS_SPEC_FUNCTION(trap)) {
throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
}
return trap;
@@ -973,7 +977,7 @@
// Clone the attributes object for protection.
// TODO(rossberg): not spec'ed yet, so not sure if this should involve
// non-own properties as it does (or non-enumerable ones, as it doesn't?).
- var attributesClone = {}
+ var attributesClone = {};
for (var a in attributes) {
attributesClone[a] = attributes[a];
}
@@ -1037,7 +1041,16 @@
if (IS_UNDEFINED(props)) {
throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
}
- %Fix(obj);
+
+ if (IS_SPEC_FUNCTION(obj)) {
+ var callTrap = %GetCallTrap(obj);
+ var constructTrap = %GetConstructTrap(obj);
+ var code = DelegateCallAndConstruct(callTrap, constructTrap);
+ %Fix(obj); // becomes a regular function
+ %SetCode(obj, code);
+ } else {
+ %Fix(obj);
+ }
ObjectDefineProperties(obj, props);
}
@@ -1168,10 +1181,11 @@
%SetExpectedNumberOfProperties($Object, 4);
// ----------------------------------------------------------------------------
+// Object
-
-function SetupObject() {
- // Setup non-enumerable functions on the Object.prototype object.
+function SetUpObject() {
+ %CheckIsBootstrapping();
+ // Set Up non-enumerable functions on the Object.prototype object.
InstallFunctions($Object.prototype, DONT_ENUM, $Array(
"toString", ObjectToString,
"toLocaleString", ObjectToLocaleString,
@@ -1201,8 +1215,7 @@
));
}
-SetupObject();
-
+SetUpObject();
// ----------------------------------------------------------------------------
// Boolean
@@ -1233,14 +1246,16 @@
// ----------------------------------------------------------------------------
-function SetupBoolean() {
+function SetUpBoolean () {
+ %CheckIsBootstrapping();
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString,
"valueOf", BooleanValueOf
));
}
-SetupBoolean();
+SetUpBoolean();
+
// ----------------------------------------------------------------------------
// Number
@@ -1354,9 +1369,10 @@
// ----------------------------------------------------------------------------
-function SetupNumber() {
+function SetUpNumber() {
+ %CheckIsBootstrapping();
%OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
- // Setup the constructor property on the Number prototype object.
+ // Set up the constructor property on the Number prototype object.
%SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
%OptimizeObjectForAddingMultipleProperties($Number, 5);
@@ -1385,7 +1401,7 @@
DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Number);
- // Setup non-enumerable functions on the Number prototype object.
+ // Set up non-enumerable functions on the Number prototype object.
InstallFunctions($Number.prototype, DONT_ENUM, $Array(
"toString", NumberToString,
"toLocaleString", NumberToLocaleString,
@@ -1396,7 +1412,7 @@
));
}
-SetupNumber();
+SetUpNumber();
// ----------------------------------------------------------------------------
@@ -1405,6 +1421,10 @@
$Function.prototype.constructor = $Function;
function FunctionSourceString(func) {
+ while (%IsJSFunctionProxy(func)) {
+ func = %GetCallTrap(func);
+ }
+
if (!IS_FUNCTION(func)) {
throw new $TypeError('Function.prototype.toString is not generic');
}
@@ -1434,12 +1454,13 @@
// ES5 15.3.4.5
function FunctionBind(this_arg) { // Length is 1.
- if (!IS_FUNCTION(this)) {
+ if (!IS_SPEC_FUNCTION(this)) {
throw new $TypeError('Bind must be called on a function');
}
// this_arg is not an argument that should be bound.
var argc_bound = (%_ArgumentsLength() || 1) - 1;
var fn = this;
+
if (argc_bound == 0) {
var result = function() {
if (%_IsConstructCall()) {
@@ -1448,8 +1469,7 @@
// materializing it and guarantee that this function will be optimized.
return %NewObjectFromBound(fn, null);
}
-
- return fn.apply(this_arg, arguments);
+ return %Apply(fn, this_arg, arguments, 0, %_ArgumentsLength());
};
} else {
var bound_args = new InternalArray(argc_bound);
@@ -1479,7 +1499,7 @@
for (var i = 0; i < argc; i++) {
args[argc_bound + i] = %_Arguments(i);
}
- return fn.apply(this_arg, args);
+ return %Apply(fn, this_arg, args, 0, argc + argc_bound);
};
}
@@ -1490,11 +1510,16 @@
// is called and make them non-enumerable and non-configurable.
// To be consistent with our normal functions we leave this as it is.
- // Set the correct length.
- var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
%FunctionRemovePrototype(result);
%FunctionSetBound(result);
- %BoundFunctionSetLength(result, length);
+ // Set the correct length. If this is a function proxy, this.length might
+ // throw, or return a bogus result. Leave length alone in that case.
+ // TODO(rossberg): This is underspecified in the current proxy proposal.
+ try {
+ var old_length = ToInteger(this.length);
+ var length = (old_length - argc_bound) > 0 ? old_length - argc_bound : 0;
+ %BoundFunctionSetLength(result, length);
+ } catch(x) {}
return result;
}
@@ -1525,11 +1550,12 @@
// ----------------------------------------------------------------------------
-function SetupFunction() {
+function SetUpFunction() {
+ %CheckIsBootstrapping();
InstallFunctions($Function.prototype, DONT_ENUM, $Array(
"bind", FunctionBind,
"toString", FunctionToString
));
}
-SetupFunction();
+SetUpFunction();
diff --git a/src/v8threads.h b/src/v8threads.h
index 3ba823a..4002bb3 100644
--- a/src/v8threads.h
+++ b/src/v8threads.h
@@ -54,6 +54,7 @@
// Get data area for archiving a thread.
char* data() { return data_; }
+
private:
explicit ThreadState(ThreadManager* thread_manager);
diff --git a/src/variables.cc b/src/variables.cc
index e82e674..971061b 100644
--- a/src/variables.cc
+++ b/src/variables.cc
@@ -53,34 +53,6 @@
}
-Property* Variable::AsProperty() const {
- return rewrite_ == NULL ? NULL : rewrite_->AsProperty();
-}
-
-
-Slot* Variable::AsSlot() const { return rewrite_; }
-
-
-bool Variable::IsStackAllocated() const {
- return rewrite_ != NULL && rewrite_->IsStackAllocated();
-}
-
-
-bool Variable::IsParameter() const {
- return rewrite_ != NULL && rewrite_->type() == Slot::PARAMETER;
-}
-
-
-bool Variable::IsStackLocal() const {
- return rewrite_ != NULL && rewrite_->type() == Slot::LOCAL;
-}
-
-
-bool Variable::IsContextSlot() const {
- return rewrite_ != NULL && rewrite_->type() == Slot::CONTEXT;
-}
-
-
Variable::Variable(Scope* scope,
Handle<String> name,
Mode mode,
@@ -90,8 +62,9 @@
name_(name),
mode_(mode),
kind_(kind),
+ location_(UNALLOCATED),
+ index_(-1),
local_if_not_shadowed_(NULL),
- rewrite_(NULL),
is_valid_LHS_(is_valid_LHS),
is_accessed_from_inner_scope_(false),
is_used_(false) {
diff --git a/src/variables.h b/src/variables.h
index 2095555..56c8dab 100644
--- a/src/variables.h
+++ b/src/variables.h
@@ -74,6 +74,33 @@
ARGUMENTS
};
+ enum Location {
+ // Before and during variable allocation, a variable whose location is
+ // not yet determined. After allocation, a variable looked up as a
+ // property on the global object (and possibly absent). name() is the
+ // variable name, index() is invalid.
+ UNALLOCATED,
+
+ // A slot in the parameter section on the stack. index() is the
+ // parameter index, counting left-to-right. The reciever is index -1;
+ // the first parameter is index 0.
+ PARAMETER,
+
+ // A slot in the local section on the stack. index() is the variable
+ // index in the stack frame, starting at 0.
+ LOCAL,
+
+ // An indexed slot in a heap context. index() is the variable index in
+ // the context object on the heap, starting at 0. scope() is the
+ // corresponding scope.
+ CONTEXT,
+
+ // A named slot in a heap context. name() is the variable name in the
+ // context object on the heap, with lookup starting at the current
+ // context. index() is invalid.
+ LOOKUP
+ };
+
Variable(Scope* scope,
Handle<String> name,
Mode mode,
@@ -83,10 +110,6 @@
// Printing support
static const char* Mode2String(Mode mode);
- // Type testing & conversion. Global variables are not slots.
- Property* AsProperty() const;
- Slot* AsSlot() const;
-
bool IsValidLeftHandSide() { return is_valid_LHS_; }
// The source code for an eval() call may refer to a variable that is
@@ -111,10 +134,12 @@
return !is_this() && name().is_identical_to(n);
}
- bool IsStackAllocated() const;
- bool IsParameter() const; // Includes 'this'.
- bool IsStackLocal() const;
- bool IsContextSlot() const;
+ bool IsUnallocated() const { return location_ == UNALLOCATED; }
+ bool IsParameter() const { return location_ == PARAMETER; }
+ bool IsStackLocal() const { return location_ == LOCAL; }
+ bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); }
+ bool IsContextSlot() const { return location_ == CONTEXT; }
+ bool IsLookupSlot() const { return location_ == LOOKUP; }
bool is_dynamic() const {
return (mode_ == DYNAMIC ||
@@ -141,20 +166,24 @@
local_if_not_shadowed_ = local;
}
- Slot* rewrite() const { return rewrite_; }
- void set_rewrite(Slot* slot) { rewrite_ = slot; }
+ Location location() const { return location_; }
+ int index() const { return index_; }
+
+ void AllocateTo(Location location, int index) {
+ location_ = location;
+ index_ = index;
+ }
private:
Scope* scope_;
Handle<String> name_;
Mode mode_;
Kind kind_;
+ Location location_;
+ int index_;
Variable* local_if_not_shadowed_;
- // Code generation.
- Slot* rewrite_;
-
// Valid as a LHS? (const and this are not valid LHS, for example)
bool is_valid_LHS_;
diff --git a/src/version.cc b/src/version.cc
index 1a7c751..7f916e1 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -33,9 +33,9 @@
// NOTE these macros are used by the SCons build script so their names
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
-#define MINOR_VERSION 5
-#define BUILD_NUMBER 10
-#define PATCH_LEVEL 24
+#define MINOR_VERSION 6
+#define BUILD_NUMBER 6
+#define PATCH_LEVEL 11
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/weakmap.js b/src/weakmap.js
index 3d261e5..5fb5151 100644
--- a/src/weakmap.js
+++ b/src/weakmap.js
@@ -80,13 +80,11 @@
// -------------------------------------------------------------------
-function SetupWeakMap() {
+(function () {
+ %CheckIsBootstrapping();
// Set up the WeakMap constructor function.
%SetCode($WeakMap, WeakMapConstructor);
- // Set up the WeakMap prototype object.
- %FunctionSetPrototype($WeakMap, new $WeakMap());
-
// Set up the constructor property on the WeakMap prototype object.
%SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
@@ -97,7 +95,4 @@
"has", WeakMapHas,
"delete", WeakMapDelete
));
-}
-
-
-SetupWeakMap();
+})();
diff --git a/src/win32-math.cc b/src/win32-math.cc
new file mode 100644
index 0000000..3410872
--- /dev/null
+++ b/src/win32-math.cc
@@ -0,0 +1,106 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
+// refer to The Open Group Base Specification for specification of the correct
+// semantics for these functions.
+// (http://www.opengroup.org/onlinepubs/000095399/)
+#ifdef _MSC_VER
+
+#undef V8_WIN32_LEAN_AND_MEAN
+#define V8_WIN32_HEADERS_FULL
+#include "win32-headers.h"
+#include <limits.h> // Required for INT_MAX etc.
+#include <math.h>
+#include <float.h> // Required for DBL_MAX and on Win32 for finite()
+#include "win32-math.h"
+
+#include "checks.h"
+
+namespace v8 {
+
+// Test for finite value - usually defined in math.h
+int isfinite(double x) {
+ return _finite(x);
+}
+
+} // namespace v8
+
+
+// Test for a NaN (not a number) value - usually defined in math.h
+int isnan(double x) {
+ return _isnan(x);
+}
+
+
+// Test for infinity - usually defined in math.h
+int isinf(double x) {
+ return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0;
+}
+
+
+// Test if x is less than y and both nominal - usually defined in math.h
+int isless(double x, double y) {
+ return isnan(x) || isnan(y) ? 0 : x < y;
+}
+
+
+// Test if x is greater than y and both nominal - usually defined in math.h
+int isgreater(double x, double y) {
+ return isnan(x) || isnan(y) ? 0 : x > y;
+}
+
+
+// Classify floating point number - usually defined in math.h
+int fpclassify(double x) {
+ // Use the MS-specific _fpclass() for classification.
+ int flags = _fpclass(x);
+
+ // Determine class. We cannot use a switch statement because
+ // the _FPCLASS_ constants are defined as flags.
+ if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL;
+ if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO;
+ if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL;
+ if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE;
+
+ // All cases should be covered by the code above.
+ ASSERT(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN));
+ return FP_NAN;
+}
+
+
+// Test sign - usually defined in math.h
+int signbit(double x) {
+ // We need to take care of the special case of both positive
+ // and negative versions of zero.
+ if (x == 0)
+ return _fpclass(x) & _FPCLASS_NZ;
+ else
+ return x < 0;
+}
+
+#endif // _MSC_VER
diff --git a/test/mjsunit/regress/regress-98773.js b/src/win32-math.h
similarity index 69%
copy from test/mjsunit/regress/regress-98773.js
copy to src/win32-math.h
index eb24eb5..6875999 100644
--- a/test/mjsunit/regress/regress-98773.js
+++ b/src/win32-math.h
@@ -25,15 +25,37 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Calling Array.sort on an external array is not supposed to crash.
+// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
+// refer to The Open Group Base Specification for specification of the correct
+// semantics for these functions.
+// (http://www.opengroup.org/onlinepubs/000095399/)
-var array = new Int16Array(23);
-array[7] = 7; array[9] = 9;
-assertEquals(23, array.length);
-assertEquals(7, array[7]);
-assertEquals(9, array[9]);
+#ifndef V8_WIN32_MATH_H_
+#define V8_WIN32_MATH_H_
-Array.prototype.sort.call(array);
-assertEquals(23, array.length);
-assertEquals(7, array[21]);
-assertEquals(9, array[22]);
+#ifndef _MSC_VER
+#error Wrong environment, expected MSVC.
+#endif // _MSC_VER
+
+enum {
+ FP_NAN,
+ FP_INFINITE,
+ FP_ZERO,
+ FP_SUBNORMAL,
+ FP_NORMAL
+};
+
+namespace v8 {
+
+int isfinite(double x);
+
+} // namespace v8
+
+int isnan(double x);
+int isinf(double x);
+int isless(double x, double y);
+int isgreater(double x, double y);
+int fpclassify(double x);
+int signbit(double x);
+
+#endif // V8_WIN32_MATH_H_
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index c23eb16..2e373fa 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -453,6 +453,7 @@
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
+
public:
explicit Scope(CpuFeature f) {
uint64_t mask = V8_UINT64_C(1) << f;
@@ -472,10 +473,12 @@
isolate_->set_enabled_cpu_features(old_enabled_);
}
}
+
private:
Isolate* isolate_;
uint64_t old_enabled_;
#else
+
public:
explicit Scope(CpuFeature f) {}
#endif
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 7c6f7e3..db06909 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -655,15 +655,16 @@
// 2. Get the function to call (passed as receiver) from the stack, check
// if it is a function.
- Label non_function;
+ Label slow, non_function;
// The function to call is at position n+1 on the stack.
__ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
__ JumpIfSmi(rdi, &non_function);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
- __ j(not_equal, &non_function);
+ __ j(not_equal, &slow);
// 3a. Patch the first argument if necessary when calling a function.
Label shift_arguments;
+ __ Set(rdx, 0); // indicate regular JS_FUNCTION
{ Label convert_to_object, use_global_receiver, patch_receiver;
// Change context eagerly in case we need the global receiver.
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
@@ -701,6 +702,7 @@
__ push(rbx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ movq(rbx, rax);
+ __ Set(rdx, 0); // indicate regular JS_FUNCTION
__ pop(rax);
__ SmiToInteger32(rax, rax);
@@ -725,14 +727,19 @@
__ jmp(&shift_arguments);
}
+ // 3b. Check for function proxy.
+ __ bind(&slow);
+ __ Set(rdx, 1); // indicate function proxy
+ __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
+ __ j(equal, &shift_arguments);
+ __ bind(&non_function);
+ __ Set(rdx, 2); // indicate non-function
- // 3b. Patch the first argument when calling a non-function. The
+ // 3c. Patch the first argument when calling a non-function. The
// CALL_NON_FUNCTION builtin expects the non-function callee as
// receiver, so overwrite the first argument which will ultimately
// become the receiver.
- __ bind(&non_function);
__ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
- __ Set(rdi, 0);
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@@ -749,13 +756,26 @@
__ decq(rax); // One fewer argument (first argument is new receiver).
}
- // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
- { Label function;
- __ testq(rdi, rdi);
- __ j(not_zero, &function);
+ // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+ // or a function proxy via CALL_FUNCTION_PROXY.
+ { Label function, non_proxy;
+ __ testq(rdx, rdx);
+ __ j(zero, &function);
__ Set(rbx, 0);
- __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(rcx, CALL_AS_METHOD);
+ __ cmpq(rdx, Immediate(1));
+ __ j(not_equal, &non_proxy);
+
+ __ pop(rdx); // return address
+ __ push(rdi); // re-add proxy object as additional argument
+ __ push(rdx);
+ __ incq(rax);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
+ __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ bind(&non_proxy);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
@@ -797,11 +817,12 @@
static const int kArgumentsOffset = 2 * kPointerSize;
static const int kReceiverOffset = 3 * kPointerSize;
static const int kFunctionOffset = 4 * kPointerSize;
+
__ push(Operand(rbp, kFunctionOffset));
__ push(Operand(rbp, kArgumentsOffset));
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
- // Check the stack for overflow. We are not trying need to catch
+ // Check the stack for overflow. We are not trying to catch
// interruptions (e.g. debug break and preemption) here, so the "real stack
// limit" is checked.
Label okay;
@@ -831,16 +852,20 @@
__ push(rax); // limit
__ push(Immediate(0)); // index
- // Change context eagerly to get the right global object if
- // necessary.
- __ movq(rdi, Operand(rbp, kFunctionOffset));
- __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
-
- // Compute the receiver.
- Label call_to_object, use_global_receiver, push_receiver;
+ // Get the receiver.
__ movq(rbx, Operand(rbp, kReceiverOffset));
+ // Check that the function is a JS function (otherwise it must be a proxy).
+ Label push_receiver;
+ __ movq(rdi, Operand(rbp, kFunctionOffset));
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+ __ j(not_equal, &push_receiver);
+
+ // Change context eagerly to get the right global object if necessary.
+ __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
// Do not transform the receiver for strict mode functions.
+ Label call_to_object, use_global_receiver;
__ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
__ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
@@ -913,14 +938,30 @@
__ j(not_equal, &loop);
// Invoke the function.
+ Label call_proxy;
ParameterCount actual(rax);
__ SmiToInteger32(rax, rax);
__ movq(rdi, Operand(rbp, kFunctionOffset));
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+ __ j(not_equal, &call_proxy);
__ InvokeFunction(rdi, actual, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
__ LeaveInternalFrame();
- __ ret(3 * kPointerSize); // remove function, receiver, and arguments
+ __ ret(3 * kPointerSize); // remove this, receiver, and arguments
+
+ // Invoke the function proxy.
+ __ bind(&call_proxy);
+ __ push(rdi); // add function proxy as last argument
+ __ incq(rax);
+ __ Set(rbx, 0);
+ __ SetCallKind(rcx, CALL_AS_METHOD);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
+ __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+ RelocInfo::CODE_TARGET);
+
+ __ LeaveInternalFrame();
+ __ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 9237a0a..df4438b 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -2712,7 +2712,7 @@
// haven't created the exception yet. Handle that in the runtime system.
// TODO(592): Rerunning the RegExp to get the stack overflow exception.
ExternalReference pending_exception_address(
- Isolate::k_pending_exception_address, isolate);
+ Isolate::kPendingExceptionAddress, isolate);
Operand pending_exception_operand =
masm->ExternalOperand(pending_exception_address, rbx);
__ movq(rax, pending_exception_operand);
@@ -3232,7 +3232,7 @@
void CallFunctionStub::Generate(MacroAssembler* masm) {
- Label slow;
+ Label slow, non_function;
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
@@ -3257,7 +3257,7 @@
__ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
// Check that the function really is a JavaScript function.
- __ JumpIfSmi(rdi, &slow);
+ __ JumpIfSmi(rdi, &non_function);
// Goto slow case if we do not have a function.
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(not_equal, &slow);
@@ -3284,15 +3284,32 @@
// Slow-case: Non-function called.
__ bind(&slow);
+ // Check for function proxy.
+ __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
+ __ j(not_equal, &non_function);
+ __ pop(rcx);
+ __ push(rdi); // put proxy as additional argument under return address
+ __ push(rcx);
+ __ Set(rax, argc_ + 1);
+ __ Set(rbx, 0);
+ __ SetCallKind(rcx, CALL_AS_FUNCTION);
+ __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
+ {
+ Handle<Code> adaptor =
+ masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ jmp(adaptor, RelocInfo::CODE_TARGET);
+ }
+
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
+ __ bind(&non_function);
__ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi);
__ Set(rax, argc_);
__ Set(rbx, 0);
+ __ SetCallKind(rcx, CALL_AS_METHOD);
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor =
Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline();
- __ SetCallKind(rcx, CALL_AS_METHOD);
__ Jump(adaptor, RelocInfo::CODE_TARGET);
}
@@ -3428,7 +3445,7 @@
// Retrieve the pending exception and clear the variable.
ExternalReference pending_exception_address(
- Isolate::k_pending_exception_address, masm->isolate());
+ Isolate::kPendingExceptionAddress, masm->isolate());
Operand pending_exception_operand =
masm->ExternalOperand(pending_exception_address);
__ movq(rax, pending_exception_operand);
@@ -3568,14 +3585,14 @@
Isolate* isolate = masm->isolate();
// Save copies of the top frame descriptor on the stack.
- ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, isolate);
+ ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, isolate);
{
Operand c_entry_fp_operand = masm->ExternalOperand(c_entry_fp);
__ push(c_entry_fp_operand);
}
// If this is the outermost JS call, set js_entry_sp value.
- ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, isolate);
+ ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate);
__ Load(rax, js_entry_sp);
__ testq(rax, rax);
__ j(not_zero, ¬_outermost_js);
@@ -3593,7 +3610,7 @@
// Caught exception: Store result (exception) in the pending
// exception field in the JSEnv and return a failure sentinel.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate);
__ Store(pending_exception, rax);
__ movq(rax, Failure::Exception(), RelocInfo::NONE);
@@ -3938,7 +3955,8 @@
// Check for 1-byte or 2-byte string.
__ bind(&flat_string);
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ testb(result_, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string);
@@ -4195,8 +4213,9 @@
Label non_ascii, allocated, ascii_data;
__ movl(rcx, r8);
__ and_(rcx, r9);
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
- __ testl(rcx, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ testl(rcx, Immediate(kStringEncodingMask));
__ j(zero, &non_ascii);
__ bind(&ascii_data);
// Allocate an acsii cons string.
@@ -4225,7 +4244,7 @@
__ cmpb(r8, Immediate(kAsciiStringTag | kAsciiDataHintTag));
__ j(equal, &ascii_data);
// Allocate a two byte cons string.
- __ AllocateConsString(rcx, rdi, no_reg, &string_add_runtime);
+ __ AllocateTwoByteConsString(rcx, rdi, no_reg, &string_add_runtime);
__ jmp(&allocated);
// Handle creating a flat result. First check that both strings are not
@@ -4254,10 +4273,11 @@
// r8: instance type of first string
// r9: instance type of second string
Label non_ascii_string_add_flat_result;
- STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag);
- __ testl(r8, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ testl(r8, Immediate(kStringEncodingMask));
__ j(zero, &non_ascii_string_add_flat_result);
- __ testl(r9, Immediate(kAsciiStringTag));
+ __ testl(r9, Immediate(kStringEncodingMask));
__ j(zero, &string_add_runtime);
__ bind(&make_flat_ascii_string);
@@ -4295,7 +4315,9 @@
// r8: instance type of first string
// r9: instance type of first string
__ bind(&non_ascii_string_add_flat_result);
- __ and_(r9, Immediate(kAsciiStringTag));
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ and_(r9, Immediate(kStringEncodingMask));
__ j(not_zero, &string_add_runtime);
// Both strings are two byte strings. As they are short they are both
// flat.
@@ -4639,9 +4661,6 @@
void SubStringStub::Generate(MacroAssembler* masm) {
Label runtime;
- if (FLAG_string_slices) {
- __ jmp(&runtime);
- }
// Stack frame on entry.
// rsp[0]: return address
// rsp[8]: to
@@ -4707,7 +4726,82 @@
__ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
__ Set(rcx, 2);
- __ bind(&result_longer_than_two);
+ if (FLAG_string_slices) {
+ Label copy_routine;
+ // If coming from the make_two_character_string path, the string
+ // is too short to be sliced anyways.
+ STATIC_ASSERT(2 < SlicedString::kMinLength);
+ __ jmp(©_routine);
+ __ bind(&result_longer_than_two);
+
+ // rax: string
+ // rbx: instance type
+ // rcx: sub string length
+ // rdx: from index (smi)
+ Label allocate_slice, sliced_string, seq_string;
+ __ cmpq(rcx, Immediate(SlicedString::kMinLength));
+ // Short slice. Copy instead of slicing.
+ __ j(less, ©_routine);
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ testb(rbx, Immediate(kStringRepresentationMask));
+ __ j(zero, &seq_string, Label::kNear);
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+ STATIC_ASSERT(kIsIndirectStringMask != 0);
+ __ testb(rbx, Immediate(kIsIndirectStringMask));
+ // External string. Jump to runtime.
+ __ j(zero, &runtime);
+
+ __ testb(rbx, Immediate(kSlicedNotConsMask));
+ __ j(not_zero, &sliced_string, Label::kNear);
+ // Cons string. Check whether it is flat, then fetch first part.
+ __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset),
+ Heap::kEmptyStringRootIndex);
+ __ j(not_equal, &runtime);
+ __ movq(rdi, FieldOperand(rax, ConsString::kFirstOffset));
+ __ jmp(&allocate_slice, Label::kNear);
+
+ __ bind(&sliced_string);
+ // Sliced string. Fetch parent and correct start index by offset.
+ __ addq(rdx, FieldOperand(rax, SlicedString::kOffsetOffset));
+ __ movq(rdi, FieldOperand(rax, SlicedString::kParentOffset));
+ __ jmp(&allocate_slice, Label::kNear);
+
+ __ bind(&seq_string);
+ // Sequential string. Just move string to the right register.
+ __ movq(rdi, rax);
+
+ __ bind(&allocate_slice);
+ // edi: underlying subject string
+ // ebx: instance type of original subject string
+ // edx: offset
+ // ecx: length
+ // Allocate new sliced string. At this point we do not reload the instance
+ // type including the string encoding because we simply rely on the info
+ // provided by the original string. It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of
+ // the newly created string's parent anyways due to externalized strings.
+ Label two_byte_slice, set_slice_header;
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ testb(rbx, Immediate(kStringEncodingMask));
+ __ j(zero, &two_byte_slice, Label::kNear);
+ __ AllocateAsciiSlicedString(rax, rbx, no_reg, &runtime);
+ __ jmp(&set_slice_header, Label::kNear);
+ __ bind(&two_byte_slice);
+ __ AllocateTwoByteSlicedString(rax, rbx, no_reg, &runtime);
+ __ bind(&set_slice_header);
+ __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx);
+ __ Integer32ToSmi(rcx, rcx);
+ __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx);
+ __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi);
+ __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset),
+ Immediate(String::kEmptyHashField));
+ __ jmp(&return_rax);
+
+ __ bind(©_routine);
+ } else {
+ __ bind(&result_longer_than_two);
+ }
// rax: string
// rbx: instance type
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index eca349e..556523f 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -51,8 +51,7 @@
class JumpPatchSite BASE_EMBEDDED {
public:
- explicit JumpPatchSite(MacroAssembler* masm)
- : masm_(masm) {
+ explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
#ifdef DEBUG
info_emitted_ = false;
#endif
@@ -187,14 +186,14 @@
// Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ movq(Operand(rsi, context_offset), rax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
@@ -232,7 +231,7 @@
: ArgumentsAccessStub::NEW_NON_STRICT_SLOW);
__ CallStub(&stub);
- Move(arguments->AsSlot(), rax, rbx, rdx);
+ SetVar(arguments, rax, rbx, rdx);
}
if (FLAG_trace) {
@@ -244,18 +243,21 @@
if (scope()->HasIllegalRedeclaration()) {
Comment cmnt(masm_, "[ Declarations");
scope()->VisitIllegalRedeclaration(this);
+
} else {
+ PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a
// constant.
if (scope()->is_function_scope() && scope()->function() != NULL) {
- EmitDeclaration(scope()->function(), Variable::CONST, NULL);
+ int ignored = 0;
+ EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
}
VisitDeclarations(scope()->declarations());
}
{ Comment cmnt(masm_, "[ Stack check");
- PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
+ PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok;
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
__ j(above_equal, &ok, Label::kNear);
@@ -355,24 +357,26 @@
}
-void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
}
-void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
- __ movq(result_register(), slot_operand);
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ codegen()->GetVar(result_register(), var);
}
-void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
- MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
- __ push(slot_operand);
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ MemOperand operand = codegen()->VarOperand(var, result_register());
+ __ push(operand);
}
-void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
- codegen()->Move(result_register(), slot);
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
+ codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -591,43 +595,53 @@
}
-MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- return Operand(rbp, SlotOffset(slot));
- case Slot::CONTEXT: {
- int context_chain_length =
- scope()->ContextChainLength(slot->var()->scope());
- __ LoadContext(scratch, context_chain_length);
- return ContextOperand(scratch, slot->index());
- }
- case Slot::LOOKUP:
- UNREACHABLE();
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+ ASSERT(var->IsStackAllocated());
+ // Offset is negative because higher indexes are at lower addresses.
+ int offset = -var->index() * kPointerSize;
+ // Adjust by a (parameter or local) base offset.
+ if (var->IsParameter()) {
+ offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+ } else {
+ offset += JavaScriptFrameConstants::kLocal0Offset;
}
- UNREACHABLE();
- return Operand(rax, 0);
+ return Operand(rbp, offset);
}
-void FullCodeGenerator::Move(Register destination, Slot* source) {
- MemOperand location = EmitSlotSearch(source, destination);
- __ movq(destination, location);
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ if (var->IsContextSlot()) {
+ int context_chain_length = scope()->ContextChainLength(var->scope());
+ __ LoadContext(scratch, context_chain_length);
+ return ContextOperand(scratch, var->index());
+ } else {
+ return StackOperand(var);
+ }
}
-void FullCodeGenerator::Move(Slot* dst,
- Register src,
- Register scratch1,
- Register scratch2) {
- ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
- ASSERT(!scratch1.is(src) && !scratch2.is(src));
- MemOperand location = EmitSlotSearch(dst, scratch1);
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ MemOperand location = VarOperand(var, dest);
+ __ movq(dest, location);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var,
+ Register src,
+ Register scratch0,
+ Register scratch1) {
+ ASSERT(var->IsContextSlot() || var->IsStackAllocated());
+ ASSERT(!scratch0.is(src));
+ ASSERT(!scratch0.is(scratch1));
+ ASSERT(!scratch1.is(src));
+ MemOperand location = VarOperand(var, scratch0);
__ movq(location, src);
// Emit the write barrier code if the location is in the heap.
- if (dst->type() == Slot::CONTEXT) {
- int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
- __ RecordWrite(scratch1, offset, src, scratch2);
+ if (var->IsContextSlot()) {
+ int offset = Context::SlotOffset(var->index());
+ __ RecordWrite(scratch0, offset, src, scratch1);
}
}
@@ -658,29 +672,33 @@
}
-void FullCodeGenerator::EmitDeclaration(Variable* variable,
+void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode,
- FunctionLiteral* function) {
- Comment cmnt(masm_, "[ Declaration");
- ASSERT(variable != NULL); // Must have been resolved.
- Slot* slot = variable->AsSlot();
- ASSERT(slot != NULL);
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
+ FunctionLiteral* function,
+ int* global_count) {
+ // If it was not possible to allocate the variable at compile time, we
+ // need to "declare" it at runtime to make sure it actually exists in the
+ // local context.
+ Variable* variable = proxy->var();
+ switch (variable->location()) {
+ case Variable::UNALLOCATED:
+ ++(*global_count);
+ break;
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ movq(Operand(rbp, SlotOffset(slot)), result_register());
+ __ movq(StackOperand(variable), result_register());
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
- __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
+ __ movq(StackOperand(variable), kScratchRegister);
}
break;
- case Slot::CONTEXT:
- // We bypass the general EmitSlotSearch because we know more about
- // this specific context.
-
+ case Variable::CONTEXT:
// The variable in the decl always resides in the current function
// context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@@ -693,22 +711,27 @@
__ Check(not_equal, "Declaration in catch context.");
}
if (function != NULL) {
+ Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function);
- __ movq(ContextOperand(rsi, slot->index()), result_register());
- int offset = Context::SlotOffset(slot->index());
+ __ movq(ContextOperand(rsi, variable->index()), result_register());
+ int offset = Context::SlotOffset(variable->index());
__ movq(rbx, rsi);
__ RecordWrite(rbx, offset, result_register(), rcx);
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
+ Comment cmnt(masm_, "[ Declaration");
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
- __ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
+ __ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
// No write barrier since the hole value is in old space.
+ PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
}
break;
- case Slot::LOOKUP: {
+ case Variable::LOOKUP: {
+ Comment cmnt(masm_, "[ Declaration");
__ push(rsi);
__ Push(variable->name());
- // Declaration nodes are always introduced in one of two modes.
+ // Declaration nodes are always introduced in one of three modes.
ASSERT(mode == Variable::VAR ||
mode == Variable::CONST ||
mode == Variable::LET);
@@ -723,7 +746,7 @@
} else if (mode == Variable::CONST || mode == Variable::LET) {
__ PushRoot(Heap::kTheHoleValueRootIndex);
} else {
- __ Push(Smi::FromInt(0)); // no initial value!
+ __ Push(Smi::FromInt(0)); // Indicates no initial value.
}
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
break;
@@ -732,18 +755,15 @@
}
-void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
- EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
-}
+void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals.
__ push(rsi); // The context is the first argument.
__ Push(pairs);
- __ Push(Smi::FromInt(is_eval() ? 1 : 0));
- __ Push(Smi::FromInt(strict_mode_flag()));
- __ CallRuntime(Runtime::kDeclareGlobals, 4);
+ __ Push(Smi::FromInt(DeclareGlobalsFlags()));
+ __ CallRuntime(Runtime::kDeclareGlobals, 3);
// Return value is ignored.
}
@@ -1048,10 +1068,9 @@
}
-void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow) {
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
+ TypeofState typeof_state,
+ Label* slow) {
Register context = rsi;
Register temp = rdx;
@@ -1101,7 +1120,7 @@
// All extension objects were empty and it is safe to use a global
// load IC call.
__ movq(rax, GlobalObjectOperand());
- __ Move(rcx, slot->var()->name());
+ __ Move(rcx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET
@@ -1110,14 +1129,13 @@
}
-MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
- Slot* slot,
- Label* slow) {
- ASSERT(slot->type() == Slot::CONTEXT);
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+ Label* slow) {
+ ASSERT(var->IsContextSlot());
Register context = rsi;
Register temp = rbx;
- for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
+ for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
if (s->num_heap_slots() > 0) {
if (s->calls_eval()) {
// Check that extension is NULL.
@@ -1137,60 +1155,31 @@
// This function is used only for loads, not stores, so it's safe to
// return an rsi-based operand (the write barrier cannot be allowed to
// destroy the rsi register).
- return ContextOperand(context, slot->index());
+ return ContextOperand(context, var->index());
}
-void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
- Slot* slot,
- TypeofState typeof_state,
- Label* slow,
- Label* done) {
+void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
+ TypeofState typeof_state,
+ Label* slow,
+ Label* done) {
// Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope
// containing the eval.
- if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
- EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
+ if (var->mode() == Variable::DYNAMIC_GLOBAL) {
+ EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done);
- } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
- Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
- Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
- if (potential_slot != NULL) {
- // Generate fast case for locals that rewrite to slots.
- __ movq(rax,
- ContextSlotOperandCheckExtensions(potential_slot, slow));
- if (potential_slot->var()->mode() == Variable::CONST) {
- __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, done);
- __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- }
- __ jmp(done);
- } else if (rewrite != NULL) {
- // Generate fast case for calls of an argument function.
- Property* property = rewrite->AsProperty();
- if (property != NULL) {
- VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
- Literal* key_literal = property->key()->AsLiteral();
- if (obj_proxy != NULL &&
- key_literal != NULL &&
- obj_proxy->IsArguments() &&
- key_literal->handle()->IsSmi()) {
- // Load arguments object if there are no eval-introduced
- // variables. Then load the argument from the arguments
- // object using keyed load.
- __ movq(rdx,
- ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
- slow));
- __ Move(rax, key_literal->handle());
- Handle<Code> ic =
- isolate()->builtins()->KeyedLoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
- __ jmp(done);
- }
- }
+ } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
+ Variable* local = var->local_if_not_shadowed();
+ __ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
+ if (local->mode() == Variable::CONST) {
+ __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, done);
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
}
+ __ jmp(done);
}
}
@@ -1200,66 +1189,58 @@
SetSourcePosition(proxy->position());
Variable* var = proxy->var();
- // Three cases: non-this global variables, lookup slots, and all other
- // types of slots.
- Slot* slot = var->AsSlot();
- ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
-
- if (slot == NULL) {
- Comment cmnt(masm_, "Global variable");
- // Use inline caching. Variable name is passed in rcx and the global
- // object on the stack.
- __ Move(rcx, var->name());
- __ movq(rax, GlobalObjectOperand());
- Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
- __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- context()->Plug(rax);
-
- } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
- Label done, slow;
-
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
-
- __ bind(&slow);
- Comment cmnt(masm_, "Lookup slot");
- __ push(rsi); // Context.
- __ Push(var->name());
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ bind(&done);
-
- context()->Plug(rax);
-
- } else {
- Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
- ? "Context slot"
- : "Stack slot");
- if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, rax);
- __ movq(rax, slot_operand);
- __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &done, Label::kNear);
- __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- __ bind(&done);
+ // Three cases: global variables, lookup variables, and all other types of
+ // variables.
+ switch (var->location()) {
+ case Variable::UNALLOCATED: {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in rcx and the global
+ // object on the stack.
+ __ Move(rcx, var->name());
+ __ movq(rax, GlobalObjectOperand());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+ __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
context()->Plug(rax);
- } else if (var->mode() == Variable::LET) {
- // Let bindings may be the hole value if they have not been initialized.
- // Throw a type error in this case.
- Label done;
- MemOperand slot_operand = EmitSlotSearch(slot, rax);
- __ movq(rax, slot_operand);
- __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &done, Label::kNear);
+ break;
+ }
+
+ case Variable::PARAMETER:
+ case Variable::LOCAL:
+ case Variable::CONTEXT: {
+ Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
+ if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
+ context()->Plug(var);
+ } else {
+ // Let and const need a read barrier.
+ Label done;
+ GetVar(rax, var);
+ __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &done, Label::kNear);
+ if (var->mode() == Variable::LET) {
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ } else { // Variable::CONST
+ __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
+ }
+ __ bind(&done);
+ context()->Plug(rax);
+ }
+ break;
+ }
+
+ case Variable::LOOKUP: {
+ Label done, slow;
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
+ __ bind(&slow);
+ Comment cmnt(masm_, "Lookup slot");
+ __ push(rsi); // Context.
__ Push(var->name());
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
context()->Plug(rax);
- } else {
- context()->Plug(slot);
+ break;
}
}
}
@@ -1279,7 +1260,7 @@
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ movq(rbx, FieldOperand(rcx, literal_offset));
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
- __ j(not_equal, &materialized);
+ __ j(not_equal, &materialized, Label::kNear);
// Create regexp literal using runtime function
// Result will be in rax.
@@ -1744,133 +1725,88 @@
void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) {
- ASSERT(var != NULL);
- ASSERT(var->is_global() || var->AsSlot() != NULL);
-
- if (var->is_global()) {
- ASSERT(!var->is_this());
- // Assignment to a global variable. Use inline caching for the
- // assignment. Right-hand-side value is passed in rax, variable name in
- // rcx, and the global object on the stack.
+ if (var->IsUnallocated()) {
+ // Global var, const, or let.
__ Move(rcx, var->name());
__ movq(rdx, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->StoreIC_Initialize_Strict()
: isolate()->builtins()->StoreIC_Initialize();
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
-
} else if (op == Token::INIT_CONST) {
- // Like var declarations, const declarations are hoisted to function
- // scope. However, unlike var initializers, const initializers are able
- // to drill a hole to that function context, even from inside a 'with'
- // context. We thus bypass the normal static scope lookup.
- Slot* slot = var->AsSlot();
- Label skip;
- switch (slot->type()) {
- case Slot::PARAMETER:
- // No const parameters.
- UNREACHABLE();
- break;
- case Slot::LOCAL:
- __ movq(rdx, Operand(rbp, SlotOffset(slot)));
- __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &skip);
- __ movq(Operand(rbp, SlotOffset(slot)), rax);
- break;
- case Slot::CONTEXT:
- case Slot::LOOKUP:
- __ push(rax);
- __ push(rsi);
- __ Push(var->name());
- __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
- break;
+ // Const initializers need a write barrier.
+ ASSERT(!var->IsParameter()); // No const parameters.
+ if (var->IsStackLocal()) {
+ Label skip;
+ __ movq(rdx, StackOperand(var));
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &skip);
+ __ movq(StackOperand(var), rax);
+ __ bind(&skip);
+ } else {
+ ASSERT(var->IsContextSlot() || var->IsLookupSlot());
+ // Like var declarations, const declarations are hoisted to function
+ // scope. However, unlike var initializers, const initializers are
+ // able to drill a hole to that function context, even from inside a
+ // 'with' context. We thus bypass the normal static scope lookup for
+ // var->IsContextSlot().
+ __ push(rax);
+ __ push(rsi);
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
}
- __ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL: {
- Label assign;
- // Check for an initialized let binding.
- __ movq(rdx, Operand(rbp, SlotOffset(slot)));
- __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &assign);
- __ Push(var->name());
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ movq(Operand(rbp, SlotOffset(slot)), rax);
- break;
- }
-
- case Slot::CONTEXT: {
- // Let variables may be the hole value if they have not been
- // initialized. Throw a type error in this case.
- Label assign;
- MemOperand target = EmitSlotSearch(slot, rcx);
- // Check for an initialized let binding.
- __ movq(rdx, target);
- __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
- __ j(not_equal, &assign, Label::kNear);
- __ Push(var->name());
- __ CallRuntime(Runtime::kThrowReferenceError, 1);
- // Perform the assignment.
- __ bind(&assign);
- __ movq(target, rax);
- // The value of the assignment is in eax. RecordWrite clobbers its
- // register arguments.
+ // Non-initializing assignment to let variable needs a write barrier.
+ if (var->IsLookupSlot()) {
+ __ push(rax); // Value.
+ __ push(rsi); // Context.
+ __ Push(var->name());
+ __ Push(Smi::FromInt(strict_mode_flag()));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
+ } else {
+ ASSERT(var->IsStackAllocated() || var->IsContextSlot());
+ Label assign;
+ MemOperand location = VarOperand(var, rcx);
+ __ movq(rdx, location);
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ j(not_equal, &assign, Label::kNear);
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kThrowReferenceError, 1);
+ __ bind(&assign);
+ __ movq(location, rax);
+ if (var->IsContextSlot()) {
__ movq(rdx, rax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(rcx, offset, rdx, rbx);
- break;
+ __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx);
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(rax); // Value.
- __ push(rsi); // Context.
- __ Push(var->name());
- __ Push(Smi::FromInt(strict_mode_flag()));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
}
+
} else if (var->mode() != Variable::CONST) {
- // Perform the assignment for non-const variables. Const assignments
- // are simply skipped.
- Slot* slot = var->AsSlot();
- switch (slot->type()) {
- case Slot::PARAMETER:
- case Slot::LOCAL:
- // Perform the assignment.
- __ movq(Operand(rbp, SlotOffset(slot)), rax);
- break;
-
- case Slot::CONTEXT: {
- MemOperand target = EmitSlotSearch(slot, rcx);
- // Perform the assignment and issue the write barrier.
- __ movq(target, rax);
- // The value of the assignment is in rax. RecordWrite clobbers its
- // register arguments.
- __ movq(rdx, rax);
- int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(rcx, offset, rdx, rbx);
- break;
+ // Assignment to var or initializing assignment to let.
+ if (var->IsStackAllocated() || var->IsContextSlot()) {
+ MemOperand location = VarOperand(var, rcx);
+ if (FLAG_debug_code && op == Token::INIT_LET) {
+ // Check for an uninitialized let binding.
+ __ movq(rdx, location);
+ __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
+ __ Check(equal, "Let binding re-initialization.");
}
-
- case Slot::LOOKUP:
- // Call the runtime for the assignment.
- __ push(rax); // Value.
- __ push(rsi); // Context.
- __ Push(var->name());
- __ Push(Smi::FromInt(strict_mode_flag()));
- __ CallRuntime(Runtime::kStoreContextSlot, 4);
- break;
+ // Perform the assignment.
+ __ movq(location, rax);
+ if (var->IsContextSlot()) {
+ __ movq(rdx, rax);
+ __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx);
+ }
+ } else {
+ ASSERT(var->IsLookupSlot());
+ __ push(rax); // Value.
+ __ push(rsi); // Context.
+ __ Push(var->name());
+ __ Push(Smi::FromInt(strict_mode_flag()));
+ __ CallRuntime(Runtime::kStoreContextSlot, 4);
}
}
+ // Non-initializing assignments to consts are ignored.
}
@@ -1990,9 +1926,8 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
@@ -2023,9 +1958,8 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
- ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
@@ -2046,8 +1980,7 @@
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, flags);
+ CallFunctionStub stub(arg_count, flags);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
@@ -2069,8 +2002,13 @@
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
- // Push the strict mode flag.
- __ Push(Smi::FromInt(strict_mode_flag()));
+ // Push the strict mode flag. In harmony mode every eval call
+ // is a strict mode eval call.
+ StrictModeFlag strict_mode = strict_mode_flag();
+ if (FLAG_harmony_block_scoping) {
+ strict_mode = kStrictMode;
+ }
+ __ Push(Smi::FromInt(strict_mode));
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
? Runtime::kResolvePossiblyDirectEvalNoLookup
@@ -2086,18 +2024,18 @@
#endif
Comment cmnt(masm_, "[ Call");
- Expression* fun = expr->expression();
- Variable* var = fun->AsVariableProxy()->AsVariable();
+ Expression* callee = expr->expression();
+ VariableProxy* proxy = callee->AsVariableProxy();
+ Property* property = callee->AsProperty();
- if (var != NULL && var->is_possibly_eval()) {
+ if (proxy != NULL && proxy->var()->is_possibly_eval()) {
// In a call to eval, we first call %ResolvePossiblyDirectEval to
- // resolve the function we need to call and the receiver of the
- // call. Then we call the resolved function using the given
- // arguments.
+ // resolve the function we need to call and the receiver of the call.
+ // Then we call the resolved function using the given arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
// Push the arguments.
@@ -2106,15 +2044,14 @@
}
// If we know that eval can only be shadowed by eval-introduced
- // variables we attempt to load the global eval function directly
- // in generated code. If we succeed, there is no need to perform a
+ // variables we attempt to load the global eval function directly in
+ // generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system.
Label done;
- if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
+ Variable* var = proxy->var();
+ if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow;
- EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow);
+ EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
// Push the function and resolve eval.
__ push(rax);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@@ -2122,13 +2059,11 @@
__ bind(&slow);
}
- // Push copy of the function (found below the arguments) and
- // resolve eval.
+ // Push a copy of the function (found below the arguments) and resolve
+ // eval.
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
- if (done.is_linked()) {
- __ bind(&done);
- }
+ __ bind(&done);
// The runtime call returns a pair of values in rax (function) and
// rdx (receiver). Touch up the stack with the right values.
@@ -2137,80 +2072,68 @@
}
// Record source position for debugger.
SetSourcePosition(expr->position());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
- CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, rax);
- } else if (var != NULL && !var->is_this() && var->is_global()) {
- // Call to a global variable.
- // Push global object as receiver for the call IC lookup.
+ } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
+ // Call to a global variable. Push global object as receiver for the
+ // call IC lookup.
__ push(GlobalObjectOperand());
- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
- } else if (var != NULL && var->AsSlot() != NULL &&
- var->AsSlot()->type() == Slot::LOOKUP) {
+ EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder());
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
-
- __ bind(&slow);
+ // Generate code for loading from variables potentially shadowed by
+ // eval-introduced variables.
+ EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
}
- // Call the runtime to find the function to call (returned in rax)
- // and the object holding it (returned in rdx).
+ __ bind(&slow);
+ // Call the runtime to find the function to call (returned in rax) and
+ // the object holding it (returned in rdx).
__ push(context_register());
- __ Push(var->name());
+ __ Push(proxy->name());
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ push(rax); // Function.
__ push(rdx); // Receiver.
- // If fast case code has been generated, emit code to push the
- // function and receiver and have the slow path jump around this
- // code.
+ // If fast case code has been generated, emit code to push the function
+ // and receiver and have the slow path jump around this code.
if (done.is_linked()) {
Label call;
__ jmp(&call, Label::kNear);
__ bind(&done);
// Push function.
__ push(rax);
- // The receiver is implicitly the global receiver. Indicate this
- // by passing the hole to the call function stub.
+ // The receiver is implicitly the global receiver. Indicate this by
+ // passing the hole to the call function stub.
__ PushRoot(Heap::kTheHoleValueRootIndex);
__ bind(&call);
}
- // The receiver is either the global receiver or an object found
- // by LoadContextSlot. That object could be the hole if the
- // receiver is implicitly the global object.
+ // The receiver is either the global receiver or an object found by
+ // LoadContextSlot. That object could be the hole if the receiver is
+ // implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
- } else if (fun->AsProperty() != NULL) {
- // Call to an object property.
- Property* prop = fun->AsProperty();
- Literal* key = prop->key()->AsLiteral();
- if (key != NULL && key->handle()->IsSymbol()) {
- // Call to a named property, use call IC.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
+ } else if (property != NULL) {
+ { PreservePositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(property->obj());
+ }
+ if (property->key()->IsPropertyName()) {
+ EmitCallWithIC(expr,
+ property->key()->AsLiteral()->handle(),
+ RelocInfo::CODE_TARGET);
} else {
- // Call to a keyed property.
- { PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(prop->obj());
- }
- EmitKeyedCallWithIC(expr, prop->key());
+ EmitKeyedCallWithIC(expr, property->key());
}
} else {
+ // Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder());
- VisitForStackValue(fun);
+ VisitForStackValue(callee);
}
// Load global receiver object.
__ movq(rbx, GlobalObjectOperand());
@@ -3550,10 +3473,9 @@
if (expr->is_jsruntime()) {
// Call the JS runtime function using a call IC.
__ Move(rcx, expr->name());
- InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
__ call(ic, mode, expr->id());
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -3568,30 +3490,31 @@
switch (expr->op()) {
case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
- Property* prop = expr->expression()->AsProperty();
- Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+ Property* property = expr->expression()->AsProperty();
+ VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (prop != NULL) {
- VisitForStackValue(prop->obj());
- VisitForStackValue(prop->key());
+ if (property != NULL) {
+ VisitForStackValue(property->obj());
+ VisitForStackValue(property->key());
__ Push(Smi::FromInt(strict_mode_flag()));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(rax);
- } else if (var != NULL) {
+ } else if (proxy != NULL) {
+ Variable* var = proxy->var();
// Delete of an unqualified identifier is disallowed in strict mode
- // but "delete this" is.
+ // but "delete this" is allowed.
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
- if (var->is_global()) {
+ if (var->IsUnallocated()) {
__ push(GlobalObjectOperand());
__ Push(var->name());
__ Push(Smi::FromInt(kNonStrictMode));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(rax);
- } else if (var->AsSlot() != NULL &&
- var->AsSlot()->type() != Slot::LOOKUP) {
- // Result of deleting non-global, non-dynamic variables is false.
- // The subexpression does not have side effects.
- context()->Plug(false);
+ } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+ // Result of deleting non-global variables is false. 'this' is
+ // not really a variable, though we implement it as one. The
+ // subexpression does not have side effects.
+ context()->Plug(var->is_this());
} else {
// Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced.
@@ -3877,7 +3800,7 @@
ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest());
- if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ if (proxy != NULL && proxy->var()->IsUnallocated()) {
Comment cmnt(masm_, "Global variable");
__ Move(rcx, proxy->name());
__ movq(rax, GlobalObjectOperand());
@@ -3887,15 +3810,12 @@
__ call(ic);
PrepareForBailout(expr, TOS_REG);
context()->Plug(rax);
- } else if (proxy != NULL &&
- proxy->var()->AsSlot() != NULL &&
- proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
+ } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
Label done, slow;
// Generate code for loading from variables potentially shadowed
// by eval-introduced variables.
- Slot* slot = proxy->var()->AsSlot();
- EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
+ EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
__ bind(&slow);
__ push(rsi);
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 990c171..9d55594 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -145,7 +145,7 @@
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
__ Test(Operand(elements, r1, times_pointer_size,
kDetailsOffset - kHeapObjectTag),
- Smi::FromInt(PropertyDetails::TypeField::mask()));
+ Smi::FromInt(PropertyDetails::TypeField::kMask));
__ j(not_zero, miss_label);
// Get the value at the masked, scaled index.
@@ -201,9 +201,9 @@
StringDictionary::kHeaderSize +
StringDictionary::kElementsStartIndex * kPointerSize;
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
- const int kTypeAndReadOnlyMask
- = (PropertyDetails::TypeField::mask() |
- PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
+ const int kTypeAndReadOnlyMask =
+ (PropertyDetails::TypeField::kMask |
+ PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
__ Test(Operand(elements,
scratch1,
times_pointer_size,
@@ -720,7 +720,6 @@
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
- NOT_IN_LOOP,
MONOMORPHIC,
extra_ic_state,
NORMAL,
@@ -1267,9 +1266,7 @@
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
- NOT_IN_LOOP,
- MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
rdx);
@@ -1372,10 +1369,8 @@
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
- NOT_IN_LOOP,
- MONOMORPHIC,
- strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
no_reg);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index c182413..9064a26 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -100,7 +100,8 @@
void LCodeGen::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LCodeGen in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -207,14 +208,14 @@
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
- Slot* slot = scope()->parameter(i)->AsSlot();
- if (slot != NULL && slot->type() == Slot::CONTEXT) {
+ Variable* var = scope()->parameter(i);
+ if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context.
- int context_offset = Context::SlotOffset(slot->index());
+ int context_offset = Context::SlotOffset(var->index());
__ movq(Operand(rsi, context_offset), rax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
@@ -2219,11 +2220,11 @@
__ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset));
__ and_(temp, Immediate(Map::kElementsKindMask));
__ shr(temp, Immediate(Map::kElementsKindShift));
- __ cmpl(temp, Immediate(JSObject::FAST_ELEMENTS));
+ __ cmpl(temp, Immediate(FAST_ELEMENTS));
__ j(equal, &ok, Label::kNear);
- __ cmpl(temp, Immediate(JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmpl(temp, Immediate(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ j(less, &fail, Label::kNear);
- __ cmpl(temp, Immediate(JSObject::LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
+ __ cmpl(temp, Immediate(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
__ j(less_equal, &ok, Label::kNear);
__ bind(&fail);
__ Abort("Check for fast or external elements failed");
@@ -2267,7 +2268,7 @@
// Load the result.
__ movq(result,
BuildFastArrayOperand(instr->elements(), instr->key(),
- JSObject::FAST_ELEMENTS,
+ FAST_ELEMENTS,
FixedArray::kHeaderSize - kHeapObjectTag));
// Check for the hole value.
@@ -2288,14 +2289,14 @@
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
- JSObject::FAST_DOUBLE_ELEMENTS,
+ FAST_DOUBLE_ELEMENTS,
offset);
__ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
}
Operand double_load_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movsd(result, double_load_operand);
}
@@ -2304,7 +2305,7 @@
Operand LCodeGen::BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset) {
Register elements_pointer_reg = ToRegister(elements_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
@@ -2325,35 +2326,35 @@
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
__ cvtss2sd(result, result);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movsd(ToDoubleRegister(instr->result()), operand);
} else {
Register result(ToRegister(instr->result()));
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ movsxbq(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
__ movzxbq(result, operand);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsxwq(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzxwq(result, operand);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ movsxlq(result, operand);
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(result, operand);
__ testl(result, result);
// TODO(danno): we could be more clever here, perhaps having a special
@@ -2361,12 +2362,12 @@
// happens, and generate code that returns a double rather than int.
DeoptimizeIf(negative, instr->environment());
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -2952,8 +2953,8 @@
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(
- arity, NOT_IN_LOOP);
+ Handle<Code> ic =
+ isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
}
@@ -2965,7 +2966,7 @@
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ Move(rcx, instr->name());
CallCode(ic, mode, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -2976,7 +2977,7 @@
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
- CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
+ CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
__ Drop(1);
@@ -2988,7 +2989,7 @@
int arity = instr->arity();
RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
Handle<Code> ic =
- isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
+ isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ Move(rcx, instr->name());
CallCode(ic, mode, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
@@ -3061,37 +3062,37 @@
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind, 0));
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
__ movss(operand, value);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movsd(operand, ToDoubleRegister(instr->value()));
} else {
Register value(ToRegister(instr->value()));
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movb(operand, value);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movw(operand, value);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(operand, value);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
@@ -3164,7 +3165,7 @@
__ bind(&have_value);
Operand double_store_operand = BuildFastArrayOperand(
- instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movsd(double_store_operand, value);
}
@@ -3251,7 +3252,8 @@
// Dispatch on the encoding: ASCII or two-byte.
Label ascii_string;
- STATIC_ASSERT(kAsciiStringTag != 0);
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ testb(result, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear);
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 0622e9d..8cb4cec 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -218,7 +218,7 @@
Operand BuildFastArrayOperand(
LOperand* elements_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind,
+ ElementsKind elements_kind,
uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation.
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 9dc925d..5fc5646 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -313,13 +313,13 @@
void LCallNamed::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
void LCallGlobal::PrintDataTo(StringStream* stream) {
- SmartPointer<char> name_string = name()->ToCString();
+ SmartArrayPointer<char> name_string = name()->ToCString();
stream->Add("%s #%d / ", *name_string, arity());
}
@@ -539,7 +539,8 @@
void LChunkBuilder::Abort(const char* format, ...) {
if (FLAG_trace_bailout) {
- SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
+ SmartArrayPointer<char> name(
+ info()->shared_info()->DebugName()->ToCString());
PrintF("Aborting LChunk building in @\"%s\": ", *name);
va_list arguments;
va_start(arguments, format);
@@ -705,9 +706,7 @@
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
- int argument_index_accumulator = 0;
- instr->set_environment(CreateEnvironment(hydrogen_env,
- &argument_index_accumulator));
+ instr->set_environment(CreateEnvironment(hydrogen_env));
return instr;
}
@@ -990,13 +989,10 @@
}
-LEnvironment* LChunkBuilder::CreateEnvironment(
- HEnvironment* hydrogen_env,
- int* argument_index_accumulator) {
+LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
if (hydrogen_env == NULL) return NULL;
- LEnvironment* outer =
- CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
+ LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
int ast_id = hydrogen_env->ast_id();
ASSERT(ast_id != AstNode::kNoNumber);
int value_count = hydrogen_env->length();
@@ -1006,6 +1002,7 @@
argument_count_,
value_count,
outer);
+ int argument_index = 0;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@@ -1014,7 +1011,7 @@
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
- op = new LArgument((*argument_index_accumulator)++);
+ op = new LArgument(argument_index++);
} else {
op = UseAny(value);
}
@@ -1844,15 +1841,15 @@
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
Representation representation(instr->representation());
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
LOperand* key = UseRegisterOrConstant(instr->key());
@@ -1861,7 +1858,7 @@
LInstruction* load_instr = DefineAsRegister(result);
// An unsigned int array load might overflow and cause a deopt, make sure it
// has an environment.
- return (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
+ return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
AssignEnvironment(load_instr) : load_instr;
}
@@ -1911,21 +1908,21 @@
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
- JSObject::ElementsKind elements_kind = instr->elements_kind();
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(representation.IsInteger32() &&
- (elements_kind != JSObject::EXTERNAL_FLOAT_ELEMENTS) &&
- (elements_kind != JSObject::EXTERNAL_DOUBLE_ELEMENTS)) ||
+ (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
+ (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
(representation.IsDouble() &&
- ((elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) ||
- (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS))));
+ ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
+ (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->external_pointer()->representation().IsExternal());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* external_pointer = UseRegister(instr->external_pointer());
bool val_is_temp_register =
- elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS;
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT_ELEMENTS;
LOperand* val = val_is_temp_register
? UseTempRegister(instr->value())
: UseRegister(instr->value());
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 05b6637..d169bf6 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -1155,7 +1155,7 @@
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -1631,7 +1631,7 @@
LOperand* external_pointer() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
- JSObject::ElementsKind elements_kind() const {
+ ElementsKind elements_kind() const {
return hydrogen()->elements_kind();
}
};
@@ -2146,8 +2146,7 @@
LInstruction* instr, int ast_id);
void ClearInstructionPendingDeoptimizationEnvironment();
- LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
- int* argument_index_accumulator);
+ LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env);
void VisitInstruction(HInstruction* current);
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index b51d531..9cfc9b6 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -2415,7 +2415,7 @@
}
// Save the current handler.
Operand handler_operand =
- ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate()));
+ ExternalOperand(ExternalReference(Isolate::kHandlerAddress, isolate()));
push(handler_operand);
// Link this handler.
movq(handler_operand, rsp);
@@ -2426,7 +2426,7 @@
ASSERT_EQ(0, StackHandlerConstants::kNextOffset);
// Unlink this handler.
Operand handler_operand =
- ExternalOperand(ExternalReference(Isolate::k_handler_address, isolate()));
+ ExternalOperand(ExternalReference(Isolate::kHandlerAddress, isolate()));
pop(handler_operand);
// Remove the remaining fields.
addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize));
@@ -2446,7 +2446,7 @@
movq(rax, value);
}
- ExternalReference handler_address(Isolate::k_handler_address, isolate());
+ ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
Operand handler_operand = ExternalOperand(handler_address);
movq(rsp, handler_operand);
// get next in chain
@@ -2482,7 +2482,7 @@
movq(rax, value);
}
// Fetch top stack handler.
- ExternalReference handler_address(Isolate::k_handler_address, isolate());
+ ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
Load(rsp, handler_address);
// Unwind the handlers until the ENTRY handler is found.
@@ -2505,12 +2505,12 @@
if (type == OUT_OF_MEMORY) {
// Set external caught exception to false.
ExternalReference external_caught(
- Isolate::k_external_caught_exception_address, isolate());
+ Isolate::kExternalCaughtExceptionAddress, isolate());
Set(rax, static_cast<int64_t>(false));
Store(external_caught, rax);
// Set pending exception and rax to out of memory exception.
- ExternalReference pending_exception(Isolate::k_pending_exception_address,
+ ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
isolate());
movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
Store(pending_exception, rax);
@@ -2567,7 +2567,7 @@
void MacroAssembler::CheckFastElements(Register map,
Label* fail,
Label::Distance distance) {
- STATIC_ASSERT(JSObject::FAST_ELEMENTS == 0);
+ STATIC_ASSERT(FAST_ELEMENTS == 0);
cmpb(FieldOperand(map, Map::kBitField2Offset),
Immediate(Map::kMaximumBitField2FastElementValue));
j(above, fail, distance);
@@ -3041,8 +3041,8 @@
movq(r14, rax); // Backup rax in callee-save register.
}
- Store(ExternalReference(Isolate::k_c_entry_fp_address, isolate()), rbp);
- Store(ExternalReference(Isolate::k_context_address, isolate()), rsi);
+ Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp);
+ Store(ExternalReference(Isolate::kContextAddress, isolate()), rsi);
}
@@ -3132,7 +3132,7 @@
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
- ExternalReference context_address(Isolate::k_context_address, isolate());
+ ExternalReference context_address(Isolate::kContextAddress, isolate());
Operand context_operand = ExternalOperand(context_address);
movq(rsi, context_operand);
#ifdef DEBUG
@@ -3140,7 +3140,7 @@
#endif
// Clear the top frame.
- ExternalReference c_entry_fp_address(Isolate::k_c_entry_fp_address,
+ ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
isolate());
Operand c_entry_fp_operand = ExternalOperand(c_entry_fp_address);
movq(c_entry_fp_operand, Immediate(0));
@@ -3303,7 +3303,7 @@
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
ASSERT_EQ(NORMAL, 0);
Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
- Smi::FromInt(PropertyDetails::TypeField::mask()));
+ Smi::FromInt(PropertyDetails::TypeField::kMask));
j(not_zero, miss);
// Get the value at the masked, scaled index.
@@ -3623,7 +3623,7 @@
}
-void MacroAssembler::AllocateConsString(Register result,
+void MacroAssembler::AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required) {
@@ -3659,6 +3659,42 @@
}
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ // Allocate heap number in new space.
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map. The other fields are left uninitialized.
+ LoadRoot(kScratchRegister, Heap::kSlicedStringMapRootIndex);
+ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
+}
+
+
+void MacroAssembler::AllocateAsciiSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required) {
+ // Allocate heap number in new space.
+ AllocateInNewSpace(SlicedString::kSize,
+ result,
+ scratch1,
+ scratch2,
+ gc_required,
+ TAG_OBJECT);
+
+ // Set the map. The other fields are left uninitialized.
+ LoadRoot(kScratchRegister, Heap::kSlicedAsciiStringMapRootIndex);
+ movq(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
+}
+
+
// Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed.
// Destination is incremented by length, source, length and scratch are
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 47ce01b..e7eb104 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -921,7 +921,7 @@
// Allocate a raw cons string object. Only the map field of the result is
// initialized.
- void AllocateConsString(Register result,
+ void AllocateTwoByteConsString(Register result,
Register scratch1,
Register scratch2,
Label* gc_required);
@@ -930,6 +930,17 @@
Register scratch2,
Label* gc_required);
+ // Allocate a raw sliced string object. Only the map field of the result is
+ // initialized.
+ void AllocateTwoByteSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+ void AllocateAsciiSlicedString(Register result,
+ Register scratch1,
+ Register scratch2,
+ Label* gc_required);
+
// ---------------------------------------------------------------------------
// Support functions.
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index 5ea7257..76d2555 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -2537,7 +2537,7 @@
// -- rsp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
MaybeObject* maybe_stub =
KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
@@ -2996,7 +2996,7 @@
// -- rsp[0] : return address
// -----------------------------------
Code* stub;
- JSObject::ElementsKind elements_kind = receiver_map->elements_kind();
+ ElementsKind elements_kind = receiver_map->elements_kind();
MaybeObject* maybe_stub = KeyedLoadElementStub(elements_kind).TryGetCode();
if (!maybe_stub->To(&stub)) return maybe_stub;
__ DispatchMap(rdx,
@@ -3227,7 +3227,7 @@
void KeyedLoadStubCompiler::GenerateLoadExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
@@ -3255,29 +3255,29 @@
__ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
// rbx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
__ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
__ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
__ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
break;
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(rcx, Operand(rbx, rcx, times_4, 0));
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
__ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
__ movsd(xmm0, Operand(rbx, rcx, times_8, 0));
break;
default:
@@ -3293,7 +3293,7 @@
// xmm0: value as double.
ASSERT(kSmiValueSize == 32);
- if (elements_kind == JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
// For the UnsignedInt array type, we need to see whether
// the value can be represented in a Smi. If not, we need to convert
// it to a HeapNumber.
@@ -3317,8 +3317,8 @@
__ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
__ movq(rax, rcx);
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
- elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
+ elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
// For the floating-point array type, we need to always allocate a
// HeapNumber.
__ AllocateHeapNumber(rcx, rbx, &slow);
@@ -3361,7 +3361,7 @@
void KeyedStoreStubCompiler::GenerateStoreExternalArray(
MacroAssembler* masm,
- JSObject::ElementsKind elements_kind) {
+ ElementsKind elements_kind) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
@@ -3391,7 +3391,7 @@
// rbx: elements array
// rdi: untagged key
Label check_heap_number;
- if (elements_kind == JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
// Float to pixel conversion is only implemented in the runtime for now.
__ JumpIfNotSmi(rax, &slow);
} else {
@@ -3402,7 +3402,7 @@
__ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
// rbx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
{ // Clamp the value to [0..255].
Label done;
__ testl(rdx, Immediate(0xFFFFFF00));
@@ -3413,39 +3413,39 @@
}
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ movw(Operand(rbx, rdi, times_2, 0), rdx);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
__ movl(Operand(rbx, rdi, times_4, 0), rdx);
break;
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
// Need to perform int-to-float conversion.
__ cvtlsi2ss(xmm0, rdx);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
break;
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
// Need to perform int-to-float conversion.
__ cvtlsi2sd(xmm0, rdx);
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
break;
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
__ ret(0);
// TODO(danno): handle heap number -> pixel array conversion
- if (elements_kind != JSObject::EXTERNAL_PIXEL_ELEMENTS) {
+ if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) {
__ bind(&check_heap_number);
// rax: value
// rcx: key (a smi)
@@ -3464,11 +3464,11 @@
// rdi: untagged index
// rbx: base pointer of external storage
// top of FPU stack: value
- if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
+ if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, xmm0);
__ movss(Operand(rbx, rdi, times_4, 0), xmm0);
__ ret(0);
- } else if (elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
+ } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0);
__ ret(0);
} else {
@@ -3482,30 +3482,30 @@
// rdi: untagged index
// rbx: base pointer of external storage
switch (elements_kind) {
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
+ case EXTERNAL_BYTE_ELEMENTS:
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
__ cvttsd2si(rdx, xmm0);
__ movb(Operand(rbx, rdi, times_1, 0), rdx);
break;
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
+ case EXTERNAL_SHORT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
__ cvttsd2si(rdx, xmm0);
__ movw(Operand(rbx, rdi, times_2, 0), rdx);
break;
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
+ case EXTERNAL_INT_ELEMENTS:
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS:
// Convert to int64, so that NaN and infinities become
// 0x8000000000000000, which is zero mod 2^32.
__ cvttsd2siq(rdx, xmm0);
__ movl(Operand(rbx, rdi, times_4, 0), rdx);
break;
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::FAST_ELEMENTS:
- case JSObject::FAST_DOUBLE_ELEMENTS:
- case JSObject::DICTIONARY_ELEMENTS:
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ case EXTERNAL_FLOAT_ELEMENTS:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ case DICTIONARY_ELEMENTS:
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
diff --git a/src/zone-inl.h b/src/zone-inl.h
index 6e2d558..4870105 100644
--- a/src/zone-inl.h
+++ b/src/zone-inl.h
@@ -55,7 +55,12 @@
// Check if the requested size is available without expanding.
Address result = position_;
- if ((position_ += size) > limit_) result = NewExpand(size);
+
+ if (size > limit_ - position_) {
+ result = NewExpand(size);
+ } else {
+ position_ += size;
+ }
// Check that the result has the proper alignment and return it.
ASSERT(IsAddressAligned(result, kAlignment, 0));
diff --git a/src/zone.cc b/src/zone.cc
index 7574778..2d14d13 100644
--- a/src/zone.cc
+++ b/src/zone.cc
@@ -168,7 +168,7 @@
// Make sure the requested size is already properly aligned and that
// there isn't enough room in the Zone to satisfy the request.
ASSERT(size == RoundDown(size, kAlignment));
- ASSERT(position_ + size > limit_);
+ ASSERT(size > limit_ - position_);
// Compute the new segment size. We use a 'high water mark'
// strategy, where we increase the segment size every time we expand
@@ -177,7 +177,13 @@
Segment* head = segment_head_;
int old_size = (head == NULL) ? 0 : head->size();
static const int kSegmentOverhead = sizeof(Segment) + kAlignment;
- int new_size = kSegmentOverhead + size + (old_size << 1);
+ int new_size_no_overhead = size + (old_size << 1);
+ int new_size = kSegmentOverhead + new_size_no_overhead;
+ // Guard against integer overflow.
+ if (new_size_no_overhead < size || new_size < kSegmentOverhead) {
+ V8::FatalProcessOutOfMemory("Zone");
+ return NULL;
+ }
if (new_size < kMinimumSegmentSize) {
new_size = kMinimumSegmentSize;
} else if (new_size > kMaximumSegmentSize) {
@@ -196,6 +202,11 @@
// Recompute 'top' and 'limit' based on the new segment.
Address result = RoundUp(segment->start(), kAlignment);
position_ = result + size;
+ // Check for address overflow.
+ if (position_ < result) {
+ V8::FatalProcessOutOfMemory("Zone");
+ return NULL;
+ }
limit_ = segment->end();
ASSERT(position_ <= limit_);
return result;
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index c0b5316..5d0cab3 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -35,7 +35,6 @@
'target_name': 'cctest',
'type': 'executable',
'dependencies': [
- '../../tools/gyp/v8.gyp:v8',
'resources',
],
'include_dirs': [
@@ -136,6 +135,20 @@
'test-platform-win32.cc',
],
}],
+ ['component=="shared_library"', {
+ # cctest can't be built against a shared library, so we need to
+ # depend on the underlying static target in that case.
+ 'conditions': [
+ ['v8_use_snapshot=="true"', {
+ 'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
+ },
+ {
+ 'dependencies': ['../../tools/gyp/v8.gyp:v8_nosnapshot'],
+ }],
+ ],
+ }, {
+ 'dependencies': ['../../tools/gyp/v8.gyp:v8'],
+ }],
],
},
{
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index b0b8eb7..c04d893 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -110,6 +110,7 @@
// This method switches threads if we are running the Threading test.
// Otherwise it does nothing.
static void Fuzz();
+
private:
static bool fuzzing_;
static int tests_being_run_;
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 78f3756..5122da5 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -76,3 +76,7 @@
[ $arch == mips ]
test-deoptimization: SKIP
test-serialize: SKIP
+
+# Tests that may time out.
+test-api/ExternalArrays: PASS || TIMEOUT
+test-api/Threading: PASS || TIMEOUT
diff --git a/test/cctest/log-eq-of-logging-and-traversal.js b/test/cctest/log-eq-of-logging-and-traversal.js
index cd52da5..05643bf 100644
--- a/test/cctest/log-eq-of-logging-and-traversal.js
+++ b/test/cctest/log-eq-of-logging-and-traversal.js
@@ -43,8 +43,7 @@
processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove },
- 'code-delete': { parsers: [parseInt],
- processor: this.processCodeDelete },
+ 'code-delete': null,
'sfi-move': { parsers: [parseInt, parseInt],
processor: this.processFunctionMove },
'shared-library': null,
@@ -73,10 +72,6 @@
this.profile.moveCode(from, to);
};
-LogProcessor.prototype.processCodeDelete = function(start) {
- this.profile.deleteCode(start);
-};
-
LogProcessor.prototype.processFunctionMove = function(from, to) {
this.profile.moveFunc(from, to);
};
@@ -132,8 +127,8 @@
"Script", "String", "RegExp", "Date", "Error"];
function entitiesEqual(entityA, entityB) {
- if (entityA === null && entityB !== null) return true;
- if (entityA !== null && entityB === null) return false;
+ if ((entityA === null && entityB !== null) ||
+ (entityA !== null && entityB === null)) return true;
return entityA.size === entityB.size && entityNamesEqual(entityA, entityB);
}
@@ -145,6 +140,8 @@
// find the same entries. We skip builtins during log parsing, but compiled
// functions traversal may erroneously recognize them as functions, so we are
// expecting more functions in traversal vs. logging.
+ // Since we don't track code deletions, logging can also report more entries
+ // than traversal.
while (l_pos < l_len && t_pos < t_len) {
var entryA = logging_entries[l_pos];
var entryB = traversal_entries[t_pos];
@@ -166,11 +163,6 @@
if (!entities_equal) equal = false;
comparison.push([entities_equal, address, entityA, entityB]);
}
- if (l_pos < l_len) equal = false;
- while (l_pos < l_len) {
- var entryA = logging_entries[l_pos++];
- comparison.push([false, entryA[0], entryA[1], null]);
- }
return [equal, comparison];
}
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 3d40a73..c1c8aae 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -4254,7 +4254,7 @@
// This test is not intended to be run, just type checked.
-static void PersistentHandles() {
+static inline void PersistentHandles() {
USE(PersistentHandles);
Local<String> str = v8_str("foo");
v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
@@ -11821,14 +11821,21 @@
CHECK_EQ(28, result->Int32Value());
i::Handle<i::Smi> value(i::Smi::FromInt(2));
- i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ i::Handle<i::Object> no_failure;
+ no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ ASSERT(!no_failure.is_null());
+ i::USE(no_failure);
CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
*value.location() = i::Smi::FromInt(256);
- i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ ASSERT(!no_failure.is_null());
+ i::USE(no_failure);
CHECK_EQ(255,
i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
*value.location() = i::Smi::FromInt(-1);
- i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ ASSERT(!no_failure.is_null());
+ i::USE(no_failure);
CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
result = CompileRun("for (var i = 0; i < 8; i++) {"
diff --git a/test/cctest/test-assembler-mips.cc b/test/cctest/test-assembler-mips.cc
index ca11a2a..a6c76f0 100644
--- a/test/cctest/test-assembler-mips.cc
+++ b/test/cctest/test-assembler-mips.cc
@@ -774,7 +774,7 @@
Assembler assm(Isolate::Current(), NULL, 0);
Label L, C;
- if (CpuFeatures::IsSupported(FPU)) {
+ if (CpuFeatures::IsSupported(FPU) && mips32r2) {
CpuFeatures::Scope scope(FPU);
// Load all structure elements to registers.
@@ -1268,7 +1268,9 @@
Label target;
__ beq(v0, v1, &target);
+ __ nop();
__ bne(v0, v1, &target);
+ __ nop();
__ bind(&target);
__ nop();
}
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index 8f226f6..2d9b012 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
-#include <wchar.h> // wint_t
+#include <wchar.h>
#include "v8.h"
@@ -75,7 +75,7 @@
uint16_t* string = NewArray<uint16_t>(length + 1);
string_obj->Write(string);
for (int j = 0; j < length; j++)
- printf("%lc", static_cast<wint_t>(string[j]));
+ printf("%lc", static_cast<wchar_t>(string[j]));
DeleteArray(string);
}
printf("\n");
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 81c487d..f567a0f 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -107,7 +107,7 @@
0x80);
processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
- processor.CodeDeleteEvent(ToAddress(0x1600));
+ processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index b7962de..45da6dc 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -157,6 +157,7 @@
Handle<Object>(debug->debug_context()->global_proxy()), DONT_ENUM,
::v8::internal::kNonStrictMode);
}
+
private:
v8::Persistent<v8::Context> context_;
};
@@ -5916,7 +5917,7 @@
private:
int port_;
- i::SmartPointer<char> body_;
+ i::SmartArrayPointer<char> body_;
i::Socket* server_; // Server socket used for bind/accept.
i::Socket* client_; // Single client connection used by the test.
i::Semaphore* listening_; // Signalled when the server is in listen mode.
diff --git a/test/cctest/test-disasm-mips.cc b/test/cctest/test-disasm-mips.cc
index 901dbc1..5ad99d7 100644
--- a/test/cctest/test-disasm-mips.cc
+++ b/test/cctest/test-disasm-mips.cc
@@ -274,23 +274,25 @@
COMPARE(srav(v0, v1, fp),
"03c31007 srav v0, v1, fp");
- COMPARE(rotr(a0, a1, 0),
- "00252002 rotr a0, a1, 0");
- COMPARE(rotr(s0, s1, 8),
- "00318202 rotr s0, s1, 8");
- COMPARE(rotr(t2, t3, 24),
- "002b5602 rotr t2, t3, 24");
- COMPARE(rotr(v0, v1, 31),
- "002317c2 rotr v0, v1, 31");
+ if (mips32r2) {
+ COMPARE(rotr(a0, a1, 0),
+ "00252002 rotr a0, a1, 0");
+ COMPARE(rotr(s0, s1, 8),
+ "00318202 rotr s0, s1, 8");
+ COMPARE(rotr(t2, t3, 24),
+ "002b5602 rotr t2, t3, 24");
+ COMPARE(rotr(v0, v1, 31),
+ "002317c2 rotr v0, v1, 31");
- COMPARE(rotrv(a0, a1, a2),
- "00c52046 rotrv a0, a1, a2");
- COMPARE(rotrv(s0, s1, s2),
- "02518046 rotrv s0, s1, s2");
- COMPARE(rotrv(t2, t3, t4),
- "018b5046 rotrv t2, t3, t4");
- COMPARE(rotrv(v0, v1, fp),
- "03c31046 rotrv v0, v1, fp");
+ COMPARE(rotrv(a0, a1, a2),
+ "00c52046 rotrv a0, a1, a2");
+ COMPARE(rotrv(s0, s1, s2),
+ "02518046 rotrv s0, s1, s2");
+ COMPARE(rotrv(t2, t3, t4),
+ "018b5046 rotrv t2, t3, t4");
+ COMPARE(rotrv(v0, v1, fp),
+ "03c31046 rotrv v0, v1, fp");
+ }
COMPARE(break_(0),
"0000000d break, code: 0x00000 (0)");
@@ -415,18 +417,21 @@
"72f6b020 clz s6, s7");
COMPARE(clz(v0, v1),
"70621020 clz v0, v1");
- COMPARE(ins_(a0, a1, 31, 1),
- "7ca4ffc4 ins a0, a1, 31, 1");
- COMPARE(ins_(s6, s7, 30, 2),
- "7ef6ff84 ins s6, s7, 30, 2");
- COMPARE(ins_(v0, v1, 0, 32),
- "7c62f804 ins v0, v1, 0, 32");
- COMPARE(ext_(a0, a1, 31, 1),
- "7ca407c0 ext a0, a1, 31, 1");
- COMPARE(ext_(s6, s7, 30, 2),
- "7ef60f80 ext s6, s7, 30, 2");
- COMPARE(ext_(v0, v1, 0, 32),
- "7c62f800 ext v0, v1, 0, 32");
+
+ if (mips32r2) {
+ COMPARE(ins_(a0, a1, 31, 1),
+ "7ca4ffc4 ins a0, a1, 31, 1");
+ COMPARE(ins_(s6, s7, 30, 2),
+ "7ef6ff84 ins s6, s7, 30, 2");
+ COMPARE(ins_(v0, v1, 0, 32),
+ "7c62f804 ins v0, v1, 0, 32");
+ COMPARE(ext_(a0, a1, 31, 1),
+ "7ca407c0 ext a0, a1, 31, 1");
+ COMPARE(ext_(s6, s7, 30, 2),
+ "7ef60f80 ext s6, s7, 30, 2");
+ COMPARE(ext_(v0, v1, 0, 32),
+ "7c62f800 ext v0, v1, 0, 32");
+ }
VERIFY_RUN();
}
diff --git a/test/cctest/test-func-name-inference.cc b/test/cctest/test-func-name-inference.cc
index bb930c8..8f405b7 100644
--- a/test/cctest/test-func-name-inference.cc
+++ b/test/cctest/test-func-name-inference.cc
@@ -41,7 +41,7 @@
using ::v8::internal::Object;
using ::v8::internal::Runtime;
using ::v8::internal::Script;
-using ::v8::internal::SmartPointer;
+using ::v8::internal::SmartArrayPointer;
using ::v8::internal::SharedFunctionInfo;
using ::v8::internal::String;
@@ -96,7 +96,7 @@
SharedFunctionInfo::cast(shared_func_info_ptr));
// Verify inferred function name.
- SmartPointer<char> inferred_name =
+ SmartArrayPointer<char> inferred_name =
shared_func_info->inferred_name()->ToCString();
CHECK_EQ(ref_inferred_name, *inferred_name);
#endif // ENABLE_DEBUGGER_SUPPORT
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 143a23c..6c2afd4 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -948,7 +948,7 @@
static int StringCmp(const char* ref, i::String* act) {
- i::SmartPointer<char> s_act = act->ToCString();
+ i::SmartArrayPointer<char> s_act = act->ToCString();
int result = strcmp(ref, *s_act);
if (result != 0)
fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, *s_act);
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index d61fde2..7360da5 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -142,6 +142,7 @@
}
virtual void Run() = 0;
+
private:
class ThreadWithSemaphore : public i::Thread {
public:
@@ -377,6 +378,7 @@
CalcFibAndCheck();
}
}
+
private:
v8::Isolate* isolate_;
};
@@ -429,6 +431,7 @@
CalcFibAndCheck();
}
}
+
private:
v8::Isolate* isolate_;
};
@@ -498,6 +501,7 @@
thread.Join();
}
}
+
private:
v8::Isolate* isolate1_;
v8::Isolate* isolate2_;
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index dfbc733..72e663c 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -25,6 +25,7 @@
namespace {
+
class ScopedLoggerInitializer {
public:
explicit ScopedLoggerInitializer(bool prof_lazy)
@@ -470,8 +471,9 @@
typedef i::NativesCollection<i::TEST> TestSources;
-// Test that logging of code create / move / delete events
-// is equivalent to traversal of a resulting heap.
+
+// Test that logging of code create / move events is equivalent to traversal of
+// a resulting heap.
TEST(EquivalenceOfLoggingAndTraversal) {
// This test needs to be run on a "clean" V8 to ensure that snapshot log
// is loaded. This is always true when running using tools/test.py because
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 8b6afdc..f5aed96 100755
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -31,14 +31,14 @@
#include "v8.h"
-#include "isolate.h"
-#include "token.h"
-#include "scanner.h"
-#include "parser.h"
-#include "utils.h"
-#include "execution.h"
-#include "preparser.h"
#include "cctest.h"
+#include "execution.h"
+#include "isolate.h"
+#include "parser.h"
+#include "preparser.h"
+#include "scanner-character-streams.h"
+#include "token.h"
+#include "utils.h"
TEST(ScanKeywords) {
struct KeywordToken {
@@ -345,7 +345,7 @@
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
size_t kProgramSize = 1024 * 1024;
- i::SmartPointer<char> program(
+ i::SmartArrayPointer<char> program(
reinterpret_cast<char*>(malloc(kProgramSize + 1)));
memset(*program, '(', kProgramSize);
program[kProgramSize] = '\0';
@@ -398,7 +398,7 @@
if (end == 0) end = length;
unsigned sub_length = end - start;
i::HandleScope test_scope;
- i::SmartPointer<i::uc16> uc16_buffer(new i::uc16[length]);
+ i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]);
for (unsigned i = 0; i < length; i++) {
uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
}
diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc
index 250ebd4..76fd244 100644
--- a/test/cctest/test-profile-generator.cc
+++ b/test/cctest/test-profile-generator.cc
@@ -37,16 +37,16 @@
TokenEnumerator te;
CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
v8::HandleScope hs;
- v8::Local<v8::String> token1(v8::String::New("1"));
+ v8::Local<v8::String> token1(v8::String::New("1x"));
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
- v8::Local<v8::String> token2(v8::String::New("2"));
+ v8::Local<v8::String> token2(v8::String::New("2x"));
CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
{
v8::HandleScope hs;
- v8::Local<v8::String> token3(v8::String::New("3"));
+ v8::Local<v8::String> token3(v8::String::New("3x"));
CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
@@ -549,13 +549,14 @@
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
- code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1800));
+ code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700)); // Deprecate bbb.
CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
- CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
- CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
- code_map.DeleteCode(ToAddress(0x1700));
+ CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
+ CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
+ TokenEnumerator::kNoSecurityToken);
+ code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
- CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
+ CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
}
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index 9f18b60..89a9112 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -30,14 +30,15 @@
#include "v8.h"
-#include "string-stream.h"
-#include "cctest.h"
-#include "zone-inl.h"
-#include "parser.h"
#include "ast.h"
+#include "char-predicates-inl.h"
+#include "cctest.h"
#include "jsregexp.h"
+#include "parser.h"
#include "regexp-macro-assembler.h"
#include "regexp-macro-assembler-irregexp.h"
+#include "string-stream.h"
+#include "zone-inl.h"
#ifdef V8_INTERPRETED_REGEXP
#include "interpreter-irregexp.h"
#else // V8_INTERPRETED_REGEXP
@@ -78,7 +79,7 @@
}
-static SmartPointer<const char> Parse(const char* input) {
+static SmartArrayPointer<const char> Parse(const char* input) {
V8::Initialize(NULL);
v8::HandleScope scope;
ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT);
@@ -87,7 +88,7 @@
CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
CHECK(result.tree != NULL);
CHECK(result.error.is_null());
- SmartPointer<const char> output = result.tree->ToString();
+ SmartArrayPointer<const char> output = result.tree->ToString();
return output;
}
@@ -390,7 +391,7 @@
CHECK(!v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
CHECK(result.tree == NULL);
CHECK(!result.error.is_null());
- SmartPointer<char> str = result.error->ToCString(ALLOW_NULLS);
+ SmartArrayPointer<char> str = result.error->ToCString(ALLOW_NULLS);
CHECK_EQ(expected, *str);
}
@@ -422,7 +423,7 @@
for (int i = 0; i <= kMaxCaptures; i++) {
accumulator.Add("()");
}
- SmartPointer<const char> many_captures(accumulator.ToCString());
+ SmartArrayPointer<const char> many_captures(accumulator.ToCString());
ExpectError(*many_captures, kTooManyCaptures);
}
diff --git a/test/cctest/test-reloc-info.cc b/test/cctest/test-reloc-info.cc
index 0378fb3..5bdc4c3 100644
--- a/test/cctest/test-reloc-info.cc
+++ b/test/cctest/test-reloc-info.cc
@@ -45,7 +45,7 @@
const int code_size = 10 * KB;
int relocation_info_size = 10 * KB;
const int buffer_size = code_size + relocation_info_size;
- SmartPointer<byte> buffer(new byte[buffer_size]);
+ SmartArrayPointer<byte> buffer(new byte[buffer_size]);
byte* pc = *buffer;
byte* buffer_end = *buffer + buffer_size;
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index 17020a3..55c2141 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -529,3 +529,32 @@
CHECK(string->IsSlicedString());
CHECK_EQ("bcdefghijklmnopqrstuvwxy", *(string->ToCString()));
}
+
+
+TEST(SliceFromSlice) {
+ // This tests whether a slice that contains the entire parent string
+ // actually creates a new string (it should not).
+ FLAG_string_slices = true;
+ InitializeVM();
+ HandleScope scope;
+ v8::Local<v8::Value> result;
+ Handle<String> string;
+ const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
+ const char* slice = "var slice = str.slice(1,-1); slice";
+ const char* slice_from_slice = "slice.slice(1,-1);";
+
+ CompileRun(init);
+ result = CompileRun(slice);
+ CHECK(result->IsString());
+ string = v8::Utils::OpenHandle(v8::String::Cast(*result));
+ CHECK(string->IsSlicedString());
+ CHECK(SlicedString::cast(*string)->parent()->IsSeqString());
+ CHECK_EQ("bcdefghijklmnopqrstuvwxy", *(string->ToCString()));
+
+ result = CompileRun(slice_from_slice);
+ CHECK(result->IsString());
+ string = v8::Utils::OpenHandle(v8::String::Cast(*result));
+ CHECK(string->IsSlicedString());
+ CHECK(SlicedString::cast(*string)->parent()->IsSeqString());
+ CHECK_EQ("cdefghijklmnopqrstuvwx", *(string->ToCString()));
+}
diff --git a/test/cctest/test-threads.cc b/test/cctest/test-threads.cc
index 59d27ab..985b9e5 100644
--- a/test/cctest/test-threads.cc
+++ b/test/cctest/test-threads.cc
@@ -161,6 +161,7 @@
}
semaphore_->Signal();
}
+
private:
i::List<i::ThreadId>* refs_;
int thread_no_;
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index e136858..e4f70df 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -195,3 +195,15 @@
}
result.Dispose();
}
+
+
+TEST(SequenceCollectorRegression) {
+ SequenceCollector<char> collector(16);
+ collector.StartSequence();
+ collector.Add('0');
+ collector.AddBlock(
+ i::Vector<const char>("12345678901234567890123456789012", 32));
+ i::Vector<char> seq = collector.EndSequence();
+ CHECK_EQ(0, strncmp("0123456789012345678901234567890123",
+ seq.start(), seq.length()));
+}
diff --git a/test/es5conform/es5conform.status b/test/es5conform/es5conform.status
index 55712ba..d095a24 100644
--- a/test/es5conform/es5conform.status
+++ b/test/es5conform/es5conform.status
@@ -75,11 +75,11 @@
# NOT IMPLEMENTED: RegExp.prototype.multiline
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215: UNIMPLEMENTED
-# All of the tests below marked SUBSETFAIL (in 15.2.3.4) fail because
+# All of the tests below marked SUBSETFAIL (in 15.2.3.4) fail because
# the tests assumes that objects can not have more properties
-# than those described in the spec - but according to spec they can
+# than those described in the spec - but according to spec they can
# have additional properties.
-# All compareArray calls in these tests could be exchanged with a
+# All compareArray calls in these tests could be exchanged with a
# isSubsetOfArray call (I will upload a patch to the es5conform site).
# SUBSETFAIL
diff --git a/test/mjsunit/array-constructor.js b/test/mjsunit/array-constructor.js
index 063ccde..bf5d3d6 100644
--- a/test/mjsunit/array-constructor.js
+++ b/test/mjsunit/array-constructor.js
@@ -73,7 +73,7 @@
a = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8);
assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8], a);
a = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
- assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a);
+ assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a);
}
@@ -91,9 +91,9 @@
var a = eval('[' + str + ']');
var b = eval('new Array(' + str + ')')
var c = eval('Array(' + str + ')')
- assertEquals(n, a.length);
- assertArrayEquals(a, b);
- assertArrayEquals(a, c);
+ assertEquals(n, a.length);
+ assertArrayEquals(a, b);
+ assertArrayEquals(a, c);
}
diff --git a/test/mjsunit/array-iteration.js b/test/mjsunit/array-iteration.js
index f11b51c..0ee2e6e 100644
--- a/test/mjsunit/array-iteration.js
+++ b/test/mjsunit/array-iteration.js
@@ -134,7 +134,7 @@
a = [0,1];
assertFalse(a.every(function(n, index, array) { array[index] = n + 1; return n == 1;}));
assertArrayEquals([1,1], a);
-
+
// Only loop through initial part of array eventhough elements are
// added.
a = [1,1];
@@ -156,23 +156,23 @@
//
(function() {
var a = [0,1,2,3,4];
-
+
// Simple use.
var result = [1,2,3,4,5];
assertArrayEquals(result, a.map(function(n) { return n + 1; }));
assertEquals(a, a);
-
+
// Use specified object as this object when calling the function.
var o = { delta: 42 }
result = [42,43,44,45,46];
assertArrayEquals(result, a.map(function(n) { return this.delta + n; }, o));
-
+
// Modify original array.
a = [0,1,2,3,4];
result = [1,2,3,4,5];
assertArrayEquals(result, a.map(function(n, index, array) { array[index] = n + 1; return n + 1;}));
assertArrayEquals(result, a);
-
+
// Only loop through initial part of array eventhough elements are
// added.
a = [0,1,2,3,4];
@@ -197,7 +197,7 @@
// Simple use.
assertTrue(a.some(function(n) { return n == 3}));
assertFalse(a.some(function(n) { return n == 5}));
-
+
// Use specified object as this object when calling the function.
var o = { element: 42 };
a = [1,42,3];
diff --git a/test/mjsunit/array-sort.js b/test/mjsunit/array-sort.js
index fd18a5b..3fa623a 100644
--- a/test/mjsunit/array-sort.js
+++ b/test/mjsunit/array-sort.js
@@ -392,7 +392,7 @@
// Test that sort calls compare function with global object as receiver,
// and with only elements of the array as arguments.
-function o(v) {
+function o(v) {
return {__proto__: o.prototype, val: v};
}
var arr = [o(1), o(2), o(4), o(8), o(16), o(32), o(64), o(128), o(256), o(-0)];
diff --git a/test/mjsunit/bugs/618.js b/test/mjsunit/bugs/618.js
index afa9929..ddc0c19 100644
--- a/test/mjsunit/bugs/618.js
+++ b/test/mjsunit/bugs/618.js
@@ -32,14 +32,14 @@
var c1 = new C1();
assertEquals(23, c1.x);
assertEquals("undefined", typeof c1.y);
-
+
// Add setter somewhere on the prototype chain after having constructed the
// first instance.
C1.prototype = { set x(value) { this.y = 23; } };
var c1 = new C1();
assertEquals("undefined", typeof c1.x);
assertEquals(23, c1.y);
-
+
// Simple class using inline constructor.
function C2() {
this.x = 23;
diff --git a/test/mjsunit/bugs/bug-618.js b/test/mjsunit/bugs/bug-618.js
index 8f47440..ae84326 100644
--- a/test/mjsunit/bugs/bug-618.js
+++ b/test/mjsunit/bugs/bug-618.js
@@ -33,11 +33,11 @@
this.x = 23;
}
-// If a setter is added to the prototype chain of a simple constructor setting
-// one of the properties assigned in the constructor then this setter is
+// If a setter is added to the prototype chain of a simple constructor setting
+// one of the properties assigned in the constructor then this setter is
// ignored when constructing new objects from the constructor.
-// This only happens if the setter is added _after_ an instance has been
+// This only happens if the setter is added _after_ an instance has been
// created.
assertEquals(23, new C().x);
diff --git a/test/mjsunit/builtins.js b/test/mjsunit/builtins.js
new file mode 100644
index 0000000..f2ad544
--- /dev/null
+++ b/test/mjsunit/builtins.js
@@ -0,0 +1,82 @@
+// 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-natives-as=builtins
+
+// Checks that all function properties of the builtin object are neither
+// writable nor configurable. Also, theose functions that are actually
+// constructors (recognized by having properties on their .prototype object),
+// have only unconfigurable properties on the prototype, and the methods
+// are also non-writable.
+
+var names = Object.getOwnPropertyNames(builtins);
+
+function isFunction(obj) {
+ return typeof obj == "function";
+}
+
+function checkConstructor(func, name) {
+ // A constructor is a function with a prototype and properties on the
+ // prototype object besides "constructor";
+ if (name.charAt(0) == "$") return;
+ if (typeof func.prototype != "object") return;
+ var propNames = Object.getOwnPropertyNames(func.prototype);
+ if (propNames.length == 0 ||
+ (propNames.length == 1 && propNames[0] == "constructor")) {
+ // Not a constructor.
+ return;
+ }
+ var proto_desc = Object.getOwnPropertyDescriptor(func, "prototype");
+ assertTrue(proto_desc.hasOwnProperty("value"), name);
+ assertFalse(proto_desc.writable, name);
+ assertFalse(proto_desc.configurable, name);
+ var prototype = proto_desc.value;
+ assertEquals(null, prototype.__proto__, name);
+ for (var i = 0; i < propNames.length; i++) {
+ var propName = propNames[i];
+ if (propName == "constructor") continue;
+ var testName = name + "-" + propName;
+ var propDesc = Object.getOwnPropertyDescriptor(prototype, propName);
+ assertTrue(propDesc.hasOwnProperty("value"), testName);
+ assertFalse(propDesc.configurable, testName);
+ if (isFunction(propDesc.value)) {
+ assertFalse(propDesc.writable, testName);
+ }
+ }
+}
+
+for (var i = 0; i < names.length; i++) {
+ var name = names[i];
+ var desc = Object.getOwnPropertyDescriptor(builtins, name);
+ assertTrue(desc.hasOwnProperty("value"));
+ var value = desc.value;
+ if (isFunction(value)) {
+ assertFalse(desc.writable, name);
+ assertFalse(desc.configurable, name);
+ checkConstructor(value, name);
+ }
+}
diff --git a/test/mjsunit/compiler/delete.js b/test/mjsunit/compiler/delete.js
index 373a1cb..2aaecb2 100644
--- a/test/mjsunit/compiler/delete.js
+++ b/test/mjsunit/compiler/delete.js
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -66,6 +66,7 @@
assertEquals(3, (function (x) { return ((delete x) || 2) + 1; })(0));
-// 'this' at toplevel is different from all other global variables---not
-// deletable.
+// 'this' is not a Reference so delete returns true (see section 11.4.1,
+// step 2 of ES 5.1).
assertEquals(true, delete this);
+assertEquals(true, (function () { return delete this; })());
diff --git a/test/mjsunit/compiler/global-accessors.js b/test/mjsunit/compiler/global-accessors.js
index bd031a8..337424d 100644
--- a/test/mjsunit/compiler/global-accessors.js
+++ b/test/mjsunit/compiler/global-accessors.js
@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This test tests that no bailouts are missing by not hitting asserts in debug
-// mode.
+// mode.
test_count_operation()
test_compound_assignment()
diff --git a/test/mjsunit/const-redecl.js b/test/mjsunit/const-redecl.js
index 26d765b..9459708 100644
--- a/test/mjsunit/const-redecl.js
+++ b/test/mjsunit/const-redecl.js
@@ -55,7 +55,7 @@
function TestGlobal(s,e) {
// Collect the global properties before the call.
var properties = [];
- for (var key in this) properties.push(key);
+ for (var key in this) properties.push(key);
// Compute the result.
var result;
try {
@@ -113,7 +113,7 @@
// Eval second definition.
TestAll("TypeError", def0 + '; eval("' + def1 + '")');
// Eval both definitions separately.
- TestAll("TypeError", 'eval("' + def0 +'"); eval("' + def1 + '")');
+ TestAll("TypeError", 'eval("' + def0 +'"); eval("' + def1 + '")');
}
diff --git a/test/mjsunit/d8-os.js b/test/mjsunit/d8-os.js
index fd6fb77..5640326 100644
--- a/test/mjsunit/d8-os.js
+++ b/test/mjsunit/d8-os.js
@@ -30,7 +30,7 @@
// implemented on Windows, and even if it were then many of the things
// we are calling would not be available.
-var TEST_DIR = "d8-os-test-directory-" + ((Math.random() * (1<<30)) | 0);
+var TEST_DIR = "/tmp/d8-os-test-directory-" + ((Math.random() * (1<<30)) | 0);
function arg_error(str) {
@@ -64,7 +64,7 @@
os.chdir(TEST_DIR);
try {
// Check the chdir worked.
- os.system('ls', ['../' + TEST_DIR]);
+ os.system('ls', [TEST_DIR]);
// Simple create dir.
os.mkdirp("dir");
// Create dir in dir.
@@ -144,7 +144,6 @@
//}
}
} finally {
- os.chdir("..");
os.system("rm", ["-r", TEST_DIR]);
}
diff --git a/test/mjsunit/date-parse.js b/test/mjsunit/date-parse.js
index a1eef66..b46e39a 100644
--- a/test/mjsunit/date-parse.js
+++ b/test/mjsunit/date-parse.js
@@ -286,7 +286,7 @@
// Negative tests.
var testCasesNegative = [
'May 25 2008 1:30 (PM)) UTC', // Bad unmatched ')' after number.
- 'May 25 2008 1:30( )AM (PM)', //
+ 'May 25 2008 1:30( )AM (PM)', //
'May 25 2008 AAA (GMT)']; // Unknown word after number.
testCasesNegative.forEach(function (s) {
diff --git a/test/mjsunit/debug-compile-event.js b/test/mjsunit/debug-compile-event.js
index b00a907..94dddfa 100644
--- a/test/mjsunit/debug-compile-event.js
+++ b/test/mjsunit/debug-compile-event.js
@@ -81,7 +81,7 @@
assertTrue('context' in msg.body.script);
// Check that we pick script name from //@ sourceURL, iff present
- assertEquals(current_source.indexOf('sourceURL') >= 0 ?
+ assertEquals(current_source.indexOf('sourceURL') >= 0 ?
'myscript.js' : undefined,
event_data.script().name());
}
diff --git a/test/mjsunit/debug-evaluate-recursive.js b/test/mjsunit/debug-evaluate-recursive.js
index 6ee391b..f34943e 100644
--- a/test/mjsunit/debug-evaluate-recursive.js
+++ b/test/mjsunit/debug-evaluate-recursive.js
@@ -110,7 +110,7 @@
if (event == Debug.DebugEvent.Break)
{
break_count++;
-
+
// Call functions with break using the FrameMirror directly.
if (break_count == 1) {
// First break event evaluates with break enabled.
diff --git a/test/mjsunit/debug-handle.js b/test/mjsunit/debug-handle.js
index 98875ce..1582b9f 100644
--- a/test/mjsunit/debug-handle.js
+++ b/test/mjsunit/debug-handle.js
@@ -72,7 +72,7 @@
// The base part of all lookup requests.
var base_request = '"seq":0,"type":"request","command":"lookup"'
-
+
// Generate request with the supplied arguments.
var request;
if (arguments) {
@@ -214,7 +214,7 @@
'Handle not in the request: ' + handle);
count++;
}
- assertEquals(count, obj.properties.length,
+ assertEquals(count, obj.properties.length,
'Unexpected number of resolved objects');
diff --git a/test/mjsunit/debug-listbreakpoints.js b/test/mjsunit/debug-listbreakpoints.js
index de0114f..1d4755f 100644
--- a/test/mjsunit/debug-listbreakpoints.js
+++ b/test/mjsunit/debug-listbreakpoints.js
@@ -39,7 +39,7 @@
// below. The test checks for these line numbers.
function g() { // line 40
- var x = 5;
+ var x = 5;
var y = 6;
var z = 7;
};
diff --git a/test/mjsunit/debug-references.js b/test/mjsunit/debug-references.js
index ab6c629..763e354 100644
--- a/test/mjsunit/debug-references.js
+++ b/test/mjsunit/debug-references.js
@@ -52,7 +52,7 @@
} else {
request = '{' + base_request + '}'
}
-
+
// Process the request and check expectation.
var response = safeEval(dcp.processDebugJSONRequest(request));
if (success) {
@@ -88,7 +88,7 @@
var response = safeEval(dcp.processDebugJSONRequest(evaluate_point));
assertTrue(response.success, "Evaluation of Point failed");
var handle = response.body.handle;
-
+
// Test some legal references requests.
testRequest(dcp, '{"handle":' + handle + ',"type":"referencedBy"}', true);
testRequest(dcp, '{"handle":' + handle + ',"type":"constructedBy"}',
diff --git a/test/mjsunit/debug-return-value.js b/test/mjsunit/debug-return-value.js
index 3982ea9..02d6a7c 100644
--- a/test/mjsunit/debug-return-value.js
+++ b/test/mjsunit/debug-return-value.js
@@ -103,12 +103,12 @@
// Position at the end of the function.
assertEquals(debugger_source_position + 50,
exec_state.frame(0).sourcePosition());
-
+
// Just about to return from the function.
assertTrue(exec_state.frame(0).isAtReturn())
assertEquals(expected_return_value,
exec_state.frame(0).returnValue().value());
-
+
// Check the same using the JSON commands.
var dcp = exec_state.debugCommandProcessor(false);
var request = '{"seq":0,"type":"request","command":"backtrace"}';
@@ -118,7 +118,7 @@
assertTrue(frames[0].atReturn);
assertEquals(expected_return_value,
response.lookup(frames[0].returnValue.ref).value);
-
+
listener_complete = true;
}
}
@@ -132,7 +132,7 @@
// Four steps from the debugger statement in this function will position us at
// the function return.
-// 0 1 2 3 4 5
+// 0 1 2 3 4 5
// 0123456789012345678901234567890123456789012345678901
function f(x) {debugger; if (x) { return 1; } else { return 2; } };
diff --git a/test/mjsunit/debug-scopes.js b/test/mjsunit/debug-scopes.js
index 40adf5b..1c23b0b 100644
--- a/test/mjsunit/debug-scopes.js
+++ b/test/mjsunit/debug-scopes.js
@@ -418,6 +418,27 @@
EndTest();
+// Nested with blocks using existing object in global code.
+BeginTest("With 6");
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.With,
+ debug.ScopeType.With,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent(with_object, 0, exec_state);
+ CheckScopeContent(with_object, 1, exec_state);
+ assertEquals(exec_state.frame().scope(0).scopeObject(), exec_state.frame().scope(1).scopeObject());
+ assertEquals(with_object, exec_state.frame().scope(1).scopeObject().value());
+};
+
+var with_object = {c:3,d:4};
+with(with_object) {
+ with(with_object) {
+ debugger;
+ }
+}
+EndTest();
+
+
// Simple closure formed by returning an inner function referering the outer
// functions arguments.
BeginTest("Closure 1");
@@ -771,6 +792,23 @@
EndTest();
+BeginTest("Closure inside With 4");
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Local,
+ debug.ScopeType.With,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x: 2}, 0, exec_state);
+ CheckScopeContent({x: 1}, 1, exec_state);
+};
+
+with({x:1}) {
+ (function(x) {
+ debugger;
+ })(2);
+}
+EndTest();
+
+
// Test global scope.
BeginTest("Global");
listener_delegate = function(exec_state) {
@@ -875,6 +913,43 @@
EndTest();
+// Test catch in global scope.
+BeginTest("Catch block 5");
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Catch,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({e:'Exception'}, 0, exec_state);
+};
+
+try {
+ throw 'Exception';
+} catch (e) {
+ debugger;
+}
+
+EndTest();
+
+
+// Closure inside catch in global code.
+BeginTest("Catch block 6");
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Local,
+ debug.ScopeType.Catch,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x: 2}, 0, exec_state);
+ CheckScopeContent({e:'Exception'}, 1, exec_state);
+};
+
+try {
+ throw 'Exception';
+} catch (e) {
+ (function(x) {
+ debugger;
+ })(2);
+}
+EndTest();
+
+
assertEquals(begin_test_count, break_count,
'one or more tests did not enter the debugger');
assertEquals(begin_test_count, end_test_count,
diff --git a/test/mjsunit/debug-step-2.js b/test/mjsunit/debug-step-2.js
new file mode 100644
index 0000000..502b426
--- /dev/null
+++ b/test/mjsunit/debug-step-2.js
@@ -0,0 +1,89 @@
+// 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-debug-as debug
+
+// This test tests that full code compiled without debug break slots
+// is recompiled with debug break slots when debugging is started.
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var bp;
+var done = false;
+var step_count = 0;
+
+// Debug event listener which steps until the global variable done is true.
+function listener(event, exec_state, event_data, data) {
+ if (event == Debug.DebugEvent.Break) {
+ if (!done) exec_state.prepareStep(Debug.StepAction.StepNext);
+ step_count++;
+ }
+};
+
+// Set the global variables state to prpare the stepping test.
+function prepare_step_test() {
+ done = false;
+ step_count = 0;
+}
+
+// Test function to step through.
+function f() {
+ var i = 1;
+ var j = 2;
+ done = true;
+};
+
+prepare_step_test();
+f();
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+bp = Debug.setBreakPoint(f, 1);
+
+prepare_step_test();
+f();
+assertEquals(4, step_count);
+Debug.clearBreakPoint(bp);
+
+// Set a breakpoint on the first var statement (line 1).
+bp = Debug.setBreakPoint(f, 1);
+
+// Step through the function ensuring that the var statements are hit as well.
+prepare_step_test();
+f();
+assertEquals(4, step_count);
+
+// Clear the breakpoint and check that no stepping happens.
+Debug.clearBreakPoint(bp);
+prepare_step_test();
+f();
+assertEquals(0, step_count);
+
+// Get rid of the debug event listener.
+Debug.setListener(null);
diff --git a/test/mjsunit/debug-stepin-call-function-stub.js b/test/mjsunit/debug-stepin-call-function-stub.js
index c5cf8fd..053b8bf 100644
--- a/test/mjsunit/debug-stepin-call-function-stub.js
+++ b/test/mjsunit/debug-stepin-call-function-stub.js
@@ -62,7 +62,7 @@
Debug.setListener(listener);
-function g() {
+function g() {
return "s"; // expected line
}
@@ -71,7 +71,7 @@
var s = 1 +f(10);
}
-function g2() {
+function g2() {
return "s2"; // expected line
}
diff --git a/test/mjsunit/debug-stepin-constructor.js b/test/mjsunit/debug-stepin-constructor.js
index 6ee3347..5549814 100644
--- a/test/mjsunit/debug-stepin-constructor.js
+++ b/test/mjsunit/debug-stepin-constructor.js
@@ -38,7 +38,7 @@
if (exec_state.frameCount() > 1) {
exec_state.prepareStep(Debug.StepAction.StepIn);
}
-
+
// Test that there is a script.
assertTrue(typeof(event_data.func().script()) == 'object');
}
diff --git a/test/mjsunit/delete-in-with.js b/test/mjsunit/delete-in-with.js
index 1efc18d..cbcfe99 100644
--- a/test/mjsunit/delete-in-with.js
+++ b/test/mjsunit/delete-in-with.js
@@ -29,6 +29,6 @@
// objects from within 'with' statements.
(function(){
var tmp = { x: 12 };
- with (tmp) { assertTrue(delete x); }
+ with (tmp) { assertTrue(delete x); }
assertFalse("x" in tmp);
})();
diff --git a/test/mjsunit/external-array.js b/test/mjsunit/external-array.js
index d7e9de0..81c6cfe 100644
--- a/test/mjsunit/external-array.js
+++ b/test/mjsunit/external-array.js
@@ -81,6 +81,19 @@
assertEquals(3.5, get(array, 1));
}
+// Test non-number parameters.
+var array_with_length_from_non_number = new Int32Array("2");
+assertEquals(2, array_with_length_from_non_number.length);
+array_with_length_from_non_number = new Int32Array(undefined);
+assertEquals(0, array_with_length_from_non_number.length);
+var foo = { valueOf: function() { return 3; } };
+array_with_length_from_non_number = new Int32Array(foo);
+assertEquals(3, array_with_length_from_non_number.length);
+foo = { toString: function() { return "4"; } };
+array_with_length_from_non_number = new Int32Array(foo);
+assertEquals(4, array_with_length_from_non_number.length);
+
+
// Test loads and stores.
types = [Array, Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array,
Uint32Array, PixelArray, Float32Array, Float64Array];
diff --git a/test/mjsunit/function-source.js b/test/mjsunit/function-source.js
index 7525775..8f2fc22 100644
--- a/test/mjsunit/function-source.js
+++ b/test/mjsunit/function-source.js
@@ -36,7 +36,7 @@
}
h();
}
-
+
function g() {
function h() {
assertEquals(Debug.scriptSource(f), Debug.scriptSource(h));
diff --git a/test/mjsunit/fuzz-natives.js b/test/mjsunit/fuzz-natives.js
index f8f0a28..ff6677e 100644
--- a/test/mjsunit/fuzz-natives.js
+++ b/test/mjsunit/fuzz-natives.js
@@ -163,6 +163,9 @@
"PromoteScheduledException": true,
"DeleteHandleScopeExtensions": true,
+ // Requires integer arguments to be non-negative.
+ "Apply": true,
+
// That can only be invoked on Array.prototype.
"FinishArrayPrototypeSetup": true,
diff --git a/test/mjsunit/get-own-property-descriptor.js b/test/mjsunit/get-own-property-descriptor.js
index 79c1fac..abb2420 100644
--- a/test/mjsunit/get-own-property-descriptor.js
+++ b/test/mjsunit/get-own-property-descriptor.js
@@ -27,7 +27,7 @@
// This file only tests very simple descriptors that always have
// configurable, enumerable, and writable set to true.
-// A range of more elaborate tests are performed in
+// A range of more elaborate tests are performed in
// object-define-property.js
function get() { return x; }
diff --git a/test/mjsunit/global-deleted-property-keyed.js b/test/mjsunit/global-deleted-property-keyed.js
index 1a1d3cb..dba3a4d 100644
--- a/test/mjsunit/global-deleted-property-keyed.js
+++ b/test/mjsunit/global-deleted-property-keyed.js
@@ -33,6 +33,6 @@
var name = "fisk";
natives[name] = name;
function foo() { natives[name] + 12; }
-for(var i = 0; i < 3; i++) foo();
+for(var i = 0; i < 3; i++) foo();
delete natives[name];
for(var i = 0; i < 3; i++) foo();
diff --git a/test/mjsunit/harmony/block-conflicts.js b/test/mjsunit/harmony/block-conflicts.js
new file mode 100644
index 0000000..8d3de6f
--- /dev/null
+++ b/test/mjsunit/harmony/block-conflicts.js
@@ -0,0 +1,126 @@
+// 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: --harmony-block-scoping
+
+// Test for conflicting variable bindings.
+
+function CheckException(e) {
+ var string = e.toString();
+ assertTrue(string.indexOf("has already been declared") >= 0 ||
+ string.indexOf("redeclaration") >= 0); return 'Conflict';
+}
+
+
+function TestFunction(s,e) {
+ try {
+ return eval("(function(){" + s + ";return " + e + "})")();
+ } catch (x) {
+ return CheckException(x);
+ }
+}
+
+
+function TestBlock(s,e) {
+ try {
+ return eval("(function(){ if (true) { " + s + "; }; return " + e + "})")();
+ } catch (x) {
+ return CheckException(x);
+ }
+}
+
+function TestAll(expected,s,opt_e) {
+ var e = "";
+ var msg = s;
+ if (opt_e) { e = opt_e; msg += "; " + opt_e; }
+ assertEquals(expected, TestFunction(s,e), "function:'" + msg + "'");
+ assertEquals(expected, TestBlock(s,e), "block:'" + msg + "'");
+}
+
+
+function TestConflict(s) {
+ TestAll('Conflict', s);
+ TestAll('Conflict', 'eval("' + s + '")');
+}
+
+
+function TestNoConflict(s) {
+ TestAll('NoConflict', s, "'NoConflict'");
+ TestAll('NoConflict', 'eval("' + s + '")', "'NoConflict'");
+}
+
+var letbinds = [ "let x",
+ "let x = 0",
+ "let x = undefined",
+ "function x() { }",
+ "let x = function() {}",
+ "let x, y",
+ "let y, x",
+ ];
+var varbinds = [ "var x",
+ "var x = 0",
+ "var x = undefined",
+ "var x = function() {}",
+ "var x, y",
+ "var y, x",
+ ];
+
+
+for (var l = 0; l < letbinds.length; ++l) {
+ // Test conflicting let/var bindings.
+ for (var v = 0; v < varbinds.length; ++v) {
+ // Same level.
+ TestConflict(letbinds[l] +'; ' + varbinds[v]);
+ TestConflict(varbinds[v] +'; ' + letbinds[l]);
+ // Different level.
+ TestConflict(letbinds[l] +'; {' + varbinds[v] + '; }');
+ TestConflict('{ ' + varbinds[v] +'; }' + letbinds[l]);
+ }
+
+ // Test conflicting let/let bindings.
+ for (var k = 0; k < letbinds.length; ++k) {
+ // Same level.
+ TestConflict(letbinds[l] +'; ' + letbinds[k]);
+ TestConflict(letbinds[k] +'; ' + letbinds[l]);
+ // Different level.
+ TestNoConflict(letbinds[l] +'; { ' + letbinds[k] + '; }');
+ TestNoConflict('{ ' + letbinds[k] +'; } ' + letbinds[l]);
+ }
+
+ // Test conflicting parameter/let bindings.
+ TestConflict('(function (x) { ' + letbinds[l] + '; })()');
+}
+
+// Test conflicting catch/var bindings.
+for (var v = 0; v < varbinds.length; ++v) {
+ TestConflict('try {} catch (x) { ' + varbinds[v] + '; }');
+}
+
+// Test conflicting parameter/var bindings.
+for (var v = 0; v < varbinds.length; ++v) {
+ TestConflict('(function (x) { ' + varbinds[v] + '; })()');
+}
diff --git a/test/mjsunit/harmony/block-leave.js b/test/mjsunit/harmony/block-leave.js
new file mode 100644
index 0000000..73eaf29
--- /dev/null
+++ b/test/mjsunit/harmony/block-leave.js
@@ -0,0 +1,225 @@
+// 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: --harmony-block-scoping
+
+// We want to test the context chain shape. In each of the tests cases
+// below, the outer with is to force a runtime lookup of the identifier 'x'
+// to actually verify that the inner context has been discarded. A static
+// lookup of 'x' might accidentally succeed.
+
+{
+ let x = 2;
+ L: {
+ let x = 3;
+ assertEquals(3, x);
+ break L;
+ assertTrue(false);
+ }
+ assertEquals(2, x);
+}
+
+do {
+ let x = 4;
+ assertEquals(4,x);
+ {
+ let x = 5;
+ assertEquals(5, x);
+ continue;
+ assertTrue(false);
+ }
+} while (false);
+
+var caught = false;
+try {
+ {
+ let xx = 18;
+ throw 25;
+ assertTrue(false);
+ }
+} catch (e) {
+ caught = true;
+ assertEquals(25, e);
+ with ({y:19}) {
+ assertEquals(19, y);
+ try {
+ // NOTE: This checks that the block scope containing xx has been
+ // removed from the context chain.
+ xx;
+ assertTrue(false); // should not reach here
+ } catch (e2) {
+ assertTrue(e2 instanceof ReferenceError);
+ }
+ }
+}
+assertTrue(caught);
+
+
+with ({x: 'outer'}) {
+ label: {
+ let x = 'inner';
+ break label;
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ label: {
+ let x = 'middle';
+ {
+ let x = 'inner';
+ break label;
+ }
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ for (var i = 0; i < 10; ++i) {
+ let x = 'inner' + i;
+ continue;
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ label: for (var i = 0; i < 10; ++i) {
+ let x = 'middle' + i;
+ for (var j = 0; j < 10; ++j) {
+ let x = 'inner' + j;
+ continue label;
+ }
+ }
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ try {
+ let x = 'inner';
+ throw 0;
+ } catch (e) {
+ assertEquals('outer', x);
+ }
+}
+
+
+with ({x: 'outer'}) {
+ try {
+ let x = 'middle';
+ {
+ let x = 'inner';
+ throw 0;
+ }
+ } catch (e) {
+ assertEquals('outer', x);
+ }
+}
+
+
+try {
+ with ({x: 'outer'}) {
+ try {
+ let x = 'inner';
+ throw 0;
+ } finally {
+ assertEquals('outer', x);
+ }
+ }
+} catch (e) {
+ if (e instanceof MjsUnitAssertionError) throw e;
+}
+
+
+try {
+ with ({x: 'outer'}) {
+ try {
+ let x = 'middle';
+ {
+ let x = 'inner';
+ throw 0;
+ }
+ } finally {
+ assertEquals('outer', x);
+ }
+ }
+} catch (e) {
+ if (e instanceof MjsUnitAssertionError) throw e;
+}
+
+
+// Verify that the context is correctly set in the stack frame after exiting
+// from with.
+function f() {}
+
+with ({x: 'outer'}) {
+ label: {
+ let x = 'inner';
+ break label;
+ }
+ f(); // The context could be restored from the stack after the call.
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ for (var i = 0; i < 10; ++i) {
+ let x = 'inner';
+ continue;
+ }
+ f();
+ assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+ try {
+ let x = 'inner';
+ throw 0;
+ } catch (e) {
+ f();
+ assertEquals('outer', x);
+ }
+}
+
+
+try {
+ with ({x: 'outer'}) {
+ try {
+ let x = 'inner';
+ throw 0;
+ } finally {
+ f();
+ assertEquals('outer', x);
+ }
+ }
+} catch (e) {
+ if (e instanceof MjsUnitAssertionError) throw e;
+}
diff --git a/test/mjsunit/harmony/block-let-declaration.js b/test/mjsunit/harmony/block-let-declaration.js
index 19c943f..49b6348 100644
--- a/test/mjsunit/harmony/block-let-declaration.js
+++ b/test/mjsunit/harmony/block-let-declaration.js
@@ -57,11 +57,9 @@
// Unprotected statement
TestLocalThrows("if (true) let x;", SyntaxError);
-TestLocalThrows("with ({}) let x;", SyntaxError);
TestLocalThrows("do let x; while (false)", SyntaxError);
TestLocalThrows("while (false) let x;", SyntaxError);
TestLocalDoesNotThrow("if (true) var x;");
-TestLocalDoesNotThrow("with ({}) var x;");
TestLocalDoesNotThrow("do var x; while (false)");
TestLocalDoesNotThrow("while (false) var x;");
diff --git a/test/mjsunit/harmony/debug-blockscopes.js b/test/mjsunit/harmony/debug-blockscopes.js
index e0df71b..0230e84 100644
--- a/test/mjsunit/harmony/debug-blockscopes.js
+++ b/test/mjsunit/harmony/debug-blockscopes.js
@@ -202,17 +202,15 @@
}
listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.Block,
- debug.ScopeType.Local,
+ CheckScopeChain([debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
CheckScopeContent({}, 0, exec_state);
- CheckScopeContent({}, 1, exec_state);
};
local_block_1();
EndTest();
-// Local scope with a parameter.
+// Simple empty block scope in local scope with a parameter.
BeginTest("Local 2");
function local_2(a) {
@@ -222,10 +220,9 @@
}
listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.Block,
- debug.ScopeType.Local,
+ CheckScopeChain([debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
- CheckScopeContent({a:1}, 1, exec_state);
+ CheckScopeContent({a:1}, 0, exec_state);
};
local_2(1);
EndTest();
@@ -266,6 +263,72 @@
EndTest();
+// Single variable in a block scope.
+BeginTest("Local 5");
+
+function local_5(a) {
+ {
+ let x = 5;
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:5}, 0, exec_state);
+ CheckScopeContent({a:1}, 1, exec_state);
+};
+local_5(1);
+EndTest();
+
+
+// Two variables in a block scope.
+BeginTest("Local 6");
+
+function local_6(a) {
+ {
+ let x = 6;
+ let y = 7;
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:6,y:7}, 0, exec_state);
+ CheckScopeContent({a:1}, 1, exec_state);
+};
+local_6(1);
+EndTest();
+
+
+// Two variables in a block scope.
+BeginTest("Local 7");
+
+function local_7(a) {
+ {
+ {
+ let x = 8;
+ debugger;
+ }
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({x:8}, 0, exec_state);
+ CheckScopeContent({a:1}, 1, exec_state);
+};
+local_7(1);
+EndTest();
+
+
// Single empty with block.
BeginTest("With block 1");
@@ -276,8 +339,7 @@
}
listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.Block,
- debug.ScopeType.With,
+ CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
CheckScopeContent({}, 0, exec_state);
@@ -299,16 +361,13 @@
}
listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.Block,
- debug.ScopeType.With,
- debug.ScopeType.Block,
+ CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.With,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
CheckScopeContent({}, 0, exec_state);
CheckScopeContent({}, 1, exec_state);
CheckScopeContent({}, 2, exec_state);
- CheckScopeContent({}, 3, exec_state);
};
with_block_2();
EndTest();
@@ -324,12 +383,10 @@
}
listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.Block,
- debug.ScopeType.With,
+ CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
- CheckScopeContent({}, 0, exec_state);
- CheckScopeContent({a:1,b:2}, 1, exec_state);
+ CheckScopeContent({a:1,b:2}, 0, exec_state);
};
with_block_3();
EndTest();
@@ -347,19 +404,39 @@
}
listener_delegate = function(exec_state) {
- CheckScopeChain([debug.ScopeType.Block,
- debug.ScopeType.With,
- debug.ScopeType.Block,
+ CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.With,
debug.ScopeType.Local,
debug.ScopeType.Global], exec_state);
- CheckScopeContent({a:2,b:1}, 1, exec_state);
- CheckScopeContent({a:1,b:2}, 3, exec_state);
+ CheckScopeContent({a:2,b:1}, 0, exec_state);
+ CheckScopeContent({a:1,b:2}, 1, exec_state);
};
with_block_4();
EndTest();
+// With block and a block local variable.
+BeginTest("With block 5");
+
+function with_block_5() {
+ with({a:1}) {
+ let a = 2;
+ debugger;
+ }
+}
+
+listener_delegate = function(exec_state) {
+ CheckScopeChain([debug.ScopeType.Block,
+ debug.ScopeType.With,
+ debug.ScopeType.Local,
+ debug.ScopeType.Global], exec_state);
+ CheckScopeContent({a:2}, 0, exec_state);
+ CheckScopeContent({a:1}, 1, exec_state);
+};
+with_block_5();
+EndTest();
+
+
// Simple closure formed by returning an inner function referering to an outer
// block local variable and an outer function's parameter.
BeginTest("Closure 1");
diff --git a/test/mjsunit/harmony/proxies.js b/test/mjsunit/harmony/proxies.js
index 640033d..3c4e5f6 100644
--- a/test/mjsunit/harmony/proxies.js
+++ b/test/mjsunit/harmony/proxies.js
@@ -1,5 +1,3 @@
-// Flags: --harmony-proxies
-
// Copyright 2008 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
@@ -27,16 +25,39 @@
// (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: --harmony-proxies
-// TODO(rossberg): test exception cases.
+
+// TODO(rossberg): for-in for proxies not implemented.
+// TODO(rossberg): inheritance from proxies not implemented.
+// TODO(rossberg): function proxies as constructors not implemented.
+
+
+// Helper.
+
+function TestWithProxies(test, handler) {
+ test(handler, Proxy.create)
+ test(handler, function(h) {return Proxy.createFunction(h, function() {})})
+}
// Getters.
function TestGet(handler) {
- var o = Proxy.create(handler)
- assertEquals(42, o.a)
- assertEquals(42, o["b"])
+ TestWithProxies(TestGet2, handler)
+}
+
+function TestGet2(handler, create) {
+ var p = create(handler)
+ assertEquals(42, p.a)
+ assertEquals(42, p["b"])
+
+ // TODO(rossberg): inheritance from proxies not yet implemented.
+ // var o = Object.create(p, {x: {value: 88}})
+ // assertEquals(42, o.a)
+ // assertEquals(42, o["b"])
+ // assertEquals(88, o.x)
+ // assertEquals(88, o["x"])
}
TestGet({
@@ -76,7 +97,11 @@
function TestGetCall(handler) {
- var p = Proxy.create(handler)
+ TestWithProxies(TestGetCall2, handler)
+}
+
+function TestGetCall2(handler, create) {
+ var p = create(handler)
assertEquals(55, p.f())
assertEquals(55, p.f("unused", "arguments"))
assertEquals(55, p.f.call(p))
@@ -139,17 +164,72 @@
}))
+function TestGetThrow(handler) {
+ TestWithProxies(TestGetThrow2, handler)
+}
+
+function TestGetThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ p.a }, "myexn")
+ assertThrows(function(){ p["b"] }, "myexn")
+}
+
+TestGetThrow({
+ get: function(r, k) { throw "myexn" }
+})
+
+TestGetThrow({
+ get: function(r, k) { return this.get2(r, k) },
+ get2: function(r, k) { throw "myexn" }
+})
+
+TestGetThrow({
+ getPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestGetThrow({
+ getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
+ getPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+TestGetThrow({
+ getPropertyDescriptor: function(k) {
+ return {get value() { throw "myexn" }}
+ }
+})
+
+TestGetThrow({
+ get: undefined,
+ getPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestGetThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestGetThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(r, k) { throw "myexn" }
+ }
+}))
+
+
// Setters.
var key
var val
-function TestSet(handler) {
- var o = Proxy.create(handler)
- assertEquals(42, o.a = 42)
+
+function TestSet(handler, create) {
+ TestWithProxies(TestSet2, handler)
+}
+
+function TestSet2(handler, create) {
+ var p = create(handler)
+ assertEquals(42, p.a = 42)
assertEquals("a", key)
assertEquals(42, val)
- assertEquals(43, o["b"] = 43)
+ assertEquals(43, p["b"] = 43)
assertEquals("b", key)
assertEquals(43, val)
}
@@ -225,31 +305,156 @@
+function TestSetThrow(handler, create) {
+ TestWithProxies(TestSetThrow2, handler)
+}
+
+function TestSetThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ p.a = 42 }, "myexn")
+ assertThrows(function(){ p["b"] = 42 }, "myexn")
+}
+
+TestSetThrow({
+ set: function(r, k, v) { throw "myexn" }
+})
+
+TestSetThrow({
+ set: function(r, k, v) { return this.set2(r, k, v) },
+ set2: function(r, k, v) { throw "myexn" }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { throw "myexn" },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { return {writable: true} },
+ defineProperty: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return this.getOwnPropertyDescriptor2(k)
+ },
+ getOwnPropertyDescriptor2: function(k) { throw "myexn" },
+ defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
+ defineProperty2: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return this.getOwnPropertyDescriptor2(k)
+ },
+ getOwnPropertyDescriptor2: function(k) { return {writable: true} },
+ defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
+ defineProperty2: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { throw "myexn" },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return {get writable() { return true }}
+ },
+ defineProperty: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return {set: function(v) { throw "myexn" }}
+ }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { throw "myexn" },
+ getPropertyDescriptor: function(k) { return {writable: true} },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) { throw "myexn" },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) { return {writable: true} },
+ defineProperty: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) {
+ return {get writable() { throw "myexn" }}
+ },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) {
+ return {set: function(v) { throw "myexn" }}
+ }
+})
+
+TestSetThrow({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) { return null },
+ defineProperty: function(k, desc) { throw "myexn" }
+})
+
+TestSetThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestSetThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(r, k, v) { throw "myexn" }
+ }
+}))
+
+
+
// Property definition (Object.defineProperty and Object.defineProperties).
var key
var desc
+
function TestDefine(handler) {
- var o = Proxy.create(handler)
- assertEquals(o, Object.defineProperty(o, "a", {value: 44}))
+ TestWithProxies(TestDefine2, handler)
+}
+
+function TestDefine2(handler, create) {
+ var p = create(handler)
+ assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
assertEquals("a", key)
assertEquals(1, Object.getOwnPropertyNames(desc).length)
assertEquals(44, desc.value)
- assertEquals(o, Object.defineProperty(o, "b", {value: 45, writable: false}))
+ assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
assertEquals("b", key)
assertEquals(2, Object.getOwnPropertyNames(desc).length)
assertEquals(45, desc.value)
assertEquals(false, desc.writable)
- assertEquals(o, Object.defineProperty(o, "c", {value: 46, enumerable: false}))
+ assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
assertEquals("c", key)
assertEquals(2, Object.getOwnPropertyNames(desc).length)
assertEquals(46, desc.value)
assertEquals(false, desc.enumerable)
var attributes = {configurable: true, mine: 66, minetoo: 23}
- assertEquals(o, Object.defineProperty(o, "d", attributes))
+ assertEquals(p, Object.defineProperty(p, "d", attributes))
assertEquals("d", key)
// Modifying the attributes object after the fact should have no effect.
attributes.configurable = false
@@ -260,23 +465,23 @@
assertEquals(66, desc.mine)
assertEquals(23, desc.minetoo)
- assertEquals(o, Object.defineProperty(o, "e", {get: function(){ return 5 }}))
+ assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
assertEquals("e", key)
assertEquals(1, Object.getOwnPropertyNames(desc).length)
assertEquals(5, desc.get())
- assertEquals(o, Object.defineProperty(o, "zzz", {}))
+ assertEquals(p, Object.defineProperty(p, "zzz", {}))
assertEquals("zzz", key)
assertEquals(0, Object.getOwnPropertyNames(desc).length)
-// TODO(rossberg): This test requires [s in proxy] to be implemented first.
-// var d = Proxy.create({
+// TODO(rossberg): This test requires for-in on proxies.
+// var d = create({
// get: function(r, k) { return (k === "value") ? 77 : void 0 },
// getOwnPropertyNames: function() { return ["value"] }
// })
// assertEquals(1, Object.getOwnPropertyNames(d).length)
// assertEquals(77, d.value)
-// assertEquals(o, Object.defineProperty(o, "p", d))
+// assertEquals(p, Object.defineProperty(p, "p", d))
// assertEquals("p", key)
// assertEquals(1, Object.getOwnPropertyNames(desc).length)
// assertEquals(77, desc.value)
@@ -288,12 +493,15 @@
last: {value: 21, configurable: true, mine: "eyes"}
}
Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
- assertEquals(o, Object.defineProperties(o, props))
+ assertEquals(p, Object.defineProperties(p, props))
assertEquals("last", key)
assertEquals(2, Object.getOwnPropertyNames(desc).length)
assertEquals(21, desc.value)
assertEquals(true, desc.configurable)
assertEquals(undefined, desc.mine) // Arguably a bug in the spec...
+
+ var props = {bla: {get value() { throw "myexn" }}}
+ assertThrows(function(){ Object.defineProperties(p, props) }, "myexn")
}
TestDefine({
@@ -312,42 +520,91 @@
}))
+function TestDefineThrow(handler) {
+ TestWithProxies(TestDefineThrow2, handler)
+}
+
+function TestDefineThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn")
+
+// TODO(rossberg): These tests require for-in on proxies.
+// var d1 = create({
+// get: function(r, k) { throw "myexn" },
+// getOwnPropertyNames: function() { return ["value"] }
+// })
+// assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
+// var d2 = create({
+// get: function(r, k) { return 77 },
+// getOwnPropertyNames: function() { throw "myexn" }
+// })
+// assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
+
+ var props = {bla: {get value() { throw "otherexn" }}}
+ assertThrows(function(){ Object.defineProperties(p, props) }, "otherexn")
+}
+
+TestDefineThrow({
+ defineProperty: function(k, d) { throw "myexn" }
+})
+
+TestDefineThrow({
+ defineProperty: function(k, d) { return this.defineProperty2(k, d) },
+ defineProperty2: function(k, d) { throw "myexn" }
+})
+
+TestDefineThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestDefineThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(k, d) { throw "myexn" }
+ }
+}))
+
+
// Property deletion (delete).
var key
+
function TestDelete(handler) {
- var o = Proxy.create(handler)
- assertEquals(true, delete o.a)
+ TestWithProxies(TestDelete2, handler)
+}
+
+function TestDelete2(handler, create) {
+ var p = create(handler)
+ assertEquals(true, delete p.a)
assertEquals("a", key)
- assertEquals(true, delete o["b"])
+ assertEquals(true, delete p["b"])
assertEquals("b", key)
- assertEquals(false, delete o.z1)
+ assertEquals(false, delete p.z1)
assertEquals("z1", key)
- assertEquals(false, delete o["z2"])
+ assertEquals(false, delete p["z2"])
assertEquals("z2", key);
(function() {
"use strict"
- assertEquals(true, delete o.c)
+ assertEquals(true, delete p.c)
assertEquals("c", key)
- assertEquals(true, delete o["d"])
+ assertEquals(true, delete p["d"])
assertEquals("d", key)
- assertThrows(function() { delete o.z3 }, TypeError)
+ assertThrows(function(){ delete p.z3 }, TypeError)
assertEquals("z3", key)
- assertThrows(function() { delete o["z4"] }, TypeError)
+ assertThrows(function(){ delete p["z4"] }, TypeError)
assertEquals("z4", key)
})()
}
TestDelete({
- 'delete': function(k) { key = k; return k < "z" }
+ delete: function(k) { key = k; return k < "z" }
})
TestDelete({
- 'delete': function(k) { return this.delete2(k) },
+ delete: function(k) { return this.delete2(k) },
delete2: function(k) { key = k; return k < "z" }
})
@@ -358,11 +615,51 @@
}))
+function TestDeleteThrow(handler) {
+ TestWithProxies(TestDeleteThrow2, handler)
+}
+
+function TestDeleteThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ delete p.a }, "myexn")
+ assertThrows(function(){ delete p["b"] }, "myexn");
+
+ (function() {
+ "use strict"
+ assertThrows(function(){ delete p.c }, "myexn")
+ assertThrows(function(){ delete p["d"] }, "myexn")
+ })()
+}
+
+TestDeleteThrow({
+ delete: function(k) { throw "myexn" }
+})
+
+TestDeleteThrow({
+ delete: function(k) { return this.delete2(k) },
+ delete2: function(k) { throw "myexn" }
+})
+
+TestDeleteThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestDeleteThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(k) { throw "myexn" }
+ }
+}))
+
+
// Property descriptors (Object.getOwnPropertyDescriptor).
function TestDescriptor(handler) {
- var o = Proxy.create(handler)
+ TestWithProxies(TestDescriptor2, handler)
+}
+
+function TestDescriptor2(handler, create) {
+ var p = create(handler)
var descs = [
{configurable: true},
{value: 34, enumerable: true, configurable: true},
@@ -371,18 +668,17 @@
{get: function() { "get" }, set: function() { "set" }, configurable: true}
]
for (var i = 0; i < descs.length; ++i) {
- assertEquals(o, Object.defineProperty(o, i, descs[i]))
- var desc = Object.getOwnPropertyDescriptor(o, i)
- for (p in descs[i]) {
+ assertEquals(p, Object.defineProperty(p, i, descs[i]))
+ var desc = Object.getOwnPropertyDescriptor(p, i)
+ for (prop in descs[i]) {
// TODO(rossberg): Ignore user attributes as long as the spec isn't
// fixed suitably.
- if (p != "mine") assertEquals(descs[i][p], desc[p])
+ if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
}
- assertEquals(undefined, Object.getOwnPropertyDescriptor(o, "absent"))
+ assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
}
}
-
TestDescriptor({
defineProperty: function(k, d) { this["__" + k] = d; return true },
getOwnPropertyDescriptor: function(k) { return this["__" + k] }
@@ -397,18 +693,43 @@
})
+function TestDescriptorThrow(handler) {
+ TestWithProxies(TestDescriptorThrow2, handler)
+}
+
+function TestDescriptorThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn")
+}
+
+TestDescriptorThrow({
+ getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestDescriptorThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return this.getOwnPropertyDescriptor2(k)
+ },
+ getOwnPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+
// Comparison.
function TestComparison(eq) {
- var o1 = Proxy.create({})
- var o2 = Proxy.create({})
+ TestWithProxies(TestComparison2, eq)
+}
- assertTrue(eq(o1, o1))
- assertTrue(eq(o2, o2))
- assertTrue(!eq(o1, o2))
- assertTrue(!eq(o1, {}))
- assertTrue(!eq({}, o2))
+function TestComparison2(eq, create) {
+ var p1 = create({})
+ var p2 = create({})
+
+ assertTrue(eq(p1, p1))
+ assertTrue(eq(p2, p2))
+ assertTrue(!eq(p1, p2))
+ assertTrue(!eq(p1, {}))
+ assertTrue(!eq({}, p2))
assertTrue(!eq({}, {}))
}
@@ -419,45 +740,61 @@
-// Type.
+// Type (typeof).
-assertEquals("object", typeof Proxy.create({}))
-assertTrue(typeof Proxy.create({}) == "object")
-assertTrue("object" == typeof Proxy.create({}))
+function TestTypeof() {
+ assertEquals("object", typeof Proxy.create({}))
+ assertTrue(typeof Proxy.create({}) == "object")
+ assertTrue("object" == typeof Proxy.create({}))
-// No function proxies yet.
+ assertEquals("function", typeof Proxy.createFunction({}, function() {}))
+ assertTrue(typeof Proxy.createFunction({}, function() {}) == "function")
+ assertTrue("function" == typeof Proxy.createFunction({}, function() {}))
+}
+
+TestTypeof()
// Membership test (in).
var key
+
function TestIn(handler) {
- var o = Proxy.create(handler)
- assertTrue("a" in o)
+ TestWithProxies(TestIn2, handler)
+}
+
+function TestIn2(handler, create) {
+ var p = create(handler)
+ assertTrue("a" in p)
assertEquals("a", key)
- assertTrue(99 in o)
+ assertTrue(99 in p)
assertEquals("99", key)
- assertFalse("z" in o)
+ assertFalse("z" in p)
assertEquals("z", key)
- if ("b" in o) {
+ assertEquals(2, ("a" in p) ? 2 : 0)
+ assertEquals(0, !("a" in p) ? 2 : 0)
+ assertEquals(0, ("zzz" in p) ? 2 : 0)
+ assertEquals(2, !("zzz" in p) ? 2 : 0)
+
+ if ("b" in p) {
} else {
assertTrue(false)
}
assertEquals("b", key)
- if ("zz" in o) {
+ if ("zz" in p) {
assertTrue(false)
}
assertEquals("zz", key)
- if (!("c" in o)) {
+ if (!("c" in p)) {
assertTrue(false)
}
assertEquals("c", key)
- if (!("zzz" in o)) {
+ if (!("zzz" in p)) {
} else {
assertTrue(false)
}
@@ -506,17 +843,70 @@
}))
+function TestInThrow(handler) {
+ TestWithProxies(TestInThrow2, handler)
+}
+
+function TestInThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ return "a" in o }, "myexn")
+ assertThrows(function(){ return !("a" in o) }, "myexn")
+ assertThrows(function(){ return ("a" in o) ? 2 : 3 }, "myexn")
+ assertThrows(function(){ if ("b" in o) {} }, "myexn")
+ assertThrows(function(){ if (!("b" in o)) {} }, "myexn")
+ assertThrows(function(){ if ("zzz" in o) {} }, "myexn")
+}
+
+TestInThrow({
+ has: function(k) { throw "myexn" }
+})
+
+TestInThrow({
+ has: function(k) { return this.has2(k) },
+ has2: function(k) { throw "myexn" }
+})
+
+TestInThrow({
+ getPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestInThrow({
+ getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
+ getPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+TestInThrow({
+ get: undefined,
+ getPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestInThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestInThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(k) { throw "myexn" }
+ }
+}))
+
+
// Own Properties (Object.prototype.hasOwnProperty).
var key
+
function TestHasOwn(handler) {
- var o = Proxy.create(handler)
- assertTrue(Object.prototype.hasOwnProperty.call(o, "a"))
+ TestWithProxies(TestHasOwn2, handler)
+}
+
+function TestHasOwn2(handler, create) {
+ var p = create(handler)
+ assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
assertEquals("a", key)
- assertTrue(Object.prototype.hasOwnProperty.call(o, 99))
+ assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
assertEquals("99", key)
- assertFalse(Object.prototype.hasOwnProperty.call(o, "z"))
+ assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
assertEquals("z", key)
}
@@ -564,6 +954,54 @@
}))
+function TestHasOwnThrow(handler) {
+ TestWithProxies(TestHasOwnThrow2, handler)
+}
+
+function TestHasOwnThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
+ "myexn")
+ assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
+ "myexn")
+}
+
+TestHasOwnThrow({
+ hasOwn: function(k) { throw "myexn" }
+})
+
+TestHasOwnThrow({
+ hasOwn: function(k) { return this.hasOwn2(k) },
+ hasOwn2: function(k) { throw "myexn" }
+})
+
+TestHasOwnThrow({
+ getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestHasOwnThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return this.getOwnPropertyDescriptor2(k)
+ },
+ getOwnPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+TestHasOwnThrow({
+ hasOwn: undefined,
+ getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestHasOwnThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestHasOwnThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(k) { throw "myexn" }
+ }
+}))
+
+
// Instanceof (instanceof)
@@ -573,29 +1011,32 @@
var p2 = Proxy.create({}, o)
var p3 = Proxy.create({}, p2)
- var f = function() {}
- f.prototype = o
+ var f0 = function() {}
+ f0.prototype = o
var f1 = function() {}
f1.prototype = p1
var f2 = function() {}
f2.prototype = p2
assertTrue(o instanceof Object)
- assertFalse(o instanceof f)
+ assertFalse(o instanceof f0)
assertFalse(o instanceof f1)
assertFalse(o instanceof f2)
assertFalse(p1 instanceof Object)
- assertFalse(p1 instanceof f)
+ assertFalse(p1 instanceof f0)
assertFalse(p1 instanceof f1)
assertFalse(p1 instanceof f2)
assertTrue(p2 instanceof Object)
- assertTrue(p2 instanceof f)
+ assertTrue(p2 instanceof f0)
assertFalse(p2 instanceof f1)
assertFalse(p2 instanceof f2)
assertTrue(p3 instanceof Object)
- assertTrue(p3 instanceof f)
+ assertTrue(p3 instanceof f0)
assertFalse(p3 instanceof f1)
assertTrue(p3 instanceof f2)
+
+ var f = Proxy.createFunction({}, function() {})
+ assertTrue(f instanceof Function)
}
TestInstanceof()
@@ -642,6 +1083,11 @@
assertTrue(Object.prototype.isPrototypeOf.call(p2, p3))
assertFalse(Object.prototype.isPrototypeOf.call(p2, p4))
assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
+
+ var f = Proxy.createFunction({}, function() {})
+ assertSame(Object.getPrototypeOf(f), Function.prototype)
+ assertTrue(Object.prototype.isPrototypeOf(f))
+ assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
}
TestPrototype()
@@ -651,8 +1097,12 @@
// Property names (Object.getOwnPropertyNames, Object.keys).
function TestPropertyNames(names, handler) {
- var p = Proxy.create(handler)
- assertArrayEquals(names, Object.getOwnPropertyNames(p))
+ TestWithProxies(TestPropertyNames2, [names, handler])
+}
+
+function TestPropertyNames2(names_handler, create) {
+ var p = create(names_handler[1])
+ assertArrayEquals(names_handler[0], Object.getOwnPropertyNames(p))
}
TestPropertyNames([], {
@@ -675,9 +1125,32 @@
})
+function TestPropertyNamesThrow(handler) {
+ TestWithProxies(TestPropertyNamesThrow2, handler)
+}
+
+function TestPropertyNamesThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ Object.getOwnPropertyNames(p) }, "myexn")
+}
+
+TestPropertyNamesThrow({
+ getOwnPropertyNames: function() { throw "myexn" }
+})
+
+TestPropertyNamesThrow({
+ getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
+ getOwnPropertyNames2: function() { throw "myexn" }
+})
+
+
function TestKeys(names, handler) {
- var p = Proxy.create(handler)
- assertArrayEquals(names, Object.keys(p))
+ TestWithProxies(TestKeys2, [names, handler])
+}
+
+function TestKeys2(names_handler, create) {
+ var p = create(names_handler[1])
+ assertArrayEquals(names_handler[0], Object.keys(p))
}
TestKeys([], {
@@ -730,10 +1203,71 @@
})
+function TestKeysThrow(handler) {
+ TestWithProxies(TestKeysThrow2, handler)
+}
+
+function TestKeysThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ Object.keys(p) }, "myexn")
+}
+
+TestKeysThrow({
+ keys: function() { throw "myexn" }
+})
+
+TestKeysThrow({
+ keys: function() { return this.keys2() },
+ keys2: function() { throw "myexn" }
+})
+
+TestKeysThrow({
+ getOwnPropertyNames: function() { throw "myexn" },
+ getOwnPropertyDescriptor: function(k) { return true }
+})
+
+TestKeysThrow({
+ getOwnPropertyNames: function() { return [1, 2] },
+ getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestKeysThrow({
+ getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
+ getOwnPropertyNames2: function() { throw "myexn" },
+})
+
+TestKeysThrow({
+ getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
+ getOwnPropertyNames2: function() { return [1, 2] },
+ getOwnPropertyDescriptor: function(k) {
+ return this.getOwnPropertyDescriptor2(k)
+ },
+ getOwnPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+TestKeysThrow({
+ get getOwnPropertyNames() { throw "myexn" }
+})
+
+TestKeysThrow({
+ get getOwnPropertyNames() {
+ return function() { throw "myexn" }
+ },
+})
+
+TestKeysThrow([], {
+ get getOwnPropertyNames() {
+ return function() { return [1, 2] }
+ },
+ getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+
// Fixing (Object.freeze, Object.seal, Object.preventExtensions,
// Object.isFrozen, Object.isSealed, Object.isExtensible)
+// TODO(rossberg): use TestWithProxies to include funciton proxies
function TestFix(names, handler) {
var proto = {p: 77}
var assertFixing = function(o, s, f, e) {
@@ -742,44 +1276,44 @@
assertEquals(e, Object.isExtensible(o))
}
- var o1 = Proxy.create(handler, proto)
- assertFixing(o1, false, false, true)
- Object.seal(o1)
- assertFixing(o1, true, names.length === 0, false)
- assertArrayEquals(names.sort(), Object.getOwnPropertyNames(o1).sort())
+ var p1 = Proxy.create(handler, proto)
+ assertFixing(p1, false, false, true)
+ Object.seal(p1)
+ assertFixing(p1, true, names.length === 0, false)
+ assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p1).sort())
assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
- Object.keys(o1).sort())
- assertEquals(proto, Object.getPrototypeOf(o1))
- assertEquals(77, o1.p)
- for (var n in o1) {
- var desc = Object.getOwnPropertyDescriptor(o1, n)
+ Object.keys(p1).sort())
+ assertEquals(proto, Object.getPrototypeOf(p1))
+ assertEquals(77, p1.p)
+ for (var n in p1) {
+ var desc = Object.getOwnPropertyDescriptor(p1, n)
if (desc !== undefined) assertFalse(desc.configurable)
}
- var o2 = Proxy.create(handler, proto)
- assertFixing(o2, false, false, true)
- Object.freeze(o2)
- assertFixing(o2, true, true, false)
- assertArrayEquals(names.sort(), Object.getOwnPropertyNames(o2).sort())
+ var p2 = Proxy.create(handler, proto)
+ assertFixing(p2, false, false, true)
+ Object.freeze(p2)
+ assertFixing(p2, true, true, false)
+ assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p2).sort())
assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
- Object.keys(o2).sort())
- assertEquals(proto, Object.getPrototypeOf(o2))
- assertEquals(77, o2.p)
- for (var n in o2) {
- var desc = Object.getOwnPropertyDescriptor(o2, n)
+ Object.keys(p2).sort())
+ assertEquals(proto, Object.getPrototypeOf(p2))
+ assertEquals(77, p2.p)
+ for (var n in p2) {
+ var desc = Object.getOwnPropertyDescriptor(p2, n)
if (desc !== undefined) assertFalse(desc.writable)
if (desc !== undefined) assertFalse(desc.configurable)
}
- var o3 = Proxy.create(handler, proto)
- assertFixing(o3, false, false, true)
- Object.preventExtensions(o3)
- assertFixing(o3, names.length === 0, names.length === 0, false)
- assertArrayEquals(names.sort(), Object.getOwnPropertyNames(o3).sort())
+ var p3 = Proxy.create(handler, proto)
+ assertFixing(p3, false, false, true)
+ Object.preventExtensions(p3)
+ assertFixing(p3, names.length === 0, names.length === 0, false)
+ assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p3).sort())
assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
- Object.keys(o3).sort())
- assertEquals(proto, Object.getPrototypeOf(o3))
- assertEquals(77, o3.p)
+ Object.keys(p3).sort())
+ assertEquals(proto, Object.getPrototypeOf(p3))
+ assertEquals(77, p3.p)
}
TestFix([], {
@@ -814,17 +1348,84 @@
})
+function TestFixFunction(fix) {
+ var f1 = Proxy.createFunction({
+ fix: function() { return {} }
+ }, function() {})
+ fix(f1)
+ assertEquals(0, f1.length)
-// String conversion (Object.prototype.toString, Object.prototype.toLocaleString)
+ var f2 = Proxy.createFunction({
+ fix: function() { return {length: {value: 3}} }
+ }, function() {})
+ fix(f2)
+ assertEquals(3, f2.length)
+
+ var f3 = Proxy.createFunction({
+ fix: function() { return {length: {value: "huh"}} }
+ }, function() {})
+ fix(f3)
+ assertEquals(0, f1.length)
+}
+
+TestFixFunction(Object.seal)
+TestFixFunction(Object.freeze)
+TestFixFunction(Object.preventExtensions)
+
+
+function TestFixThrow(handler) {
+ TestWithProxies(TestFixThrow2, handler)
+}
+
+function TestFixThrow2(handler) {
+ var p = Proxy.create(handler, {})
+ assertThrows(function(){ Object.seal(p) }, "myexn")
+ assertThrows(function(){ Object.freeze(p) }, "myexn")
+ assertThrows(function(){ Object.preventExtensions(p) }, "myexn")
+}
+
+TestFixThrow({
+ fix: function() { throw "myexn" }
+})
+
+TestFixThrow({
+ fix: function() { return this.fix2() },
+ fix2: function() { throw "myexn" }
+})
+
+TestFixThrow({
+ get fix() { throw "myexn" }
+})
+
+TestFixThrow({
+ get fix() {
+ return function() { throw "myexn" }
+ }
+})
+
+
+
+// String conversion (Object.prototype.toString,
+// Object.prototype.toLocaleString,
+// Function.prototype.toString)
var key
+
function TestToString(handler) {
- var o = Proxy.create(handler)
+ var p = Proxy.create(handler)
key = ""
- assertEquals("[object Object]", Object.prototype.toString.call(o))
+ assertEquals("[object Object]", Object.prototype.toString.call(p))
assertEquals("", key)
- assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
+ assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
assertEquals("toString", key)
+
+ var f = Proxy.createFunction(handler, function() {})
+ key = ""
+ assertEquals("[object Function]", Object.prototype.toString.call(f))
+ assertEquals("", key)
+ assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
+ assertEquals("toString", key)
+ assertDoesNotThrow(function(){ Function.prototype.toString.call(f) })
}
TestToString({
@@ -843,12 +1444,50 @@
}))
+function TestToStringThrow(handler) {
+ var p = Proxy.create(handler)
+ assertEquals("[object Object]", Object.prototype.toString.call(p))
+ assertThrows(function(){ Object.prototype.toLocaleString.call(p) }, "myexn")
+
+ var f = Proxy.createFunction(handler, function() {})
+ assertEquals("[object Function]", Object.prototype.toString.call(f))
+ assertThrows(function(){ Object.prototype.toLocaleString.call(f) }, "myexn")
+}
+
+TestToStringThrow({
+ get: function(r, k) { throw "myexn" }
+})
+
+TestToStringThrow({
+ get: function(r, k) { return function() { throw "myexn" } }
+})
+
+TestToStringThrow({
+ get: function(r, k) { return this.get2(r, k) },
+ get2: function(r, k) { throw "myexn" }
+})
+
+TestToStringThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestToStringThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(r, k) { throw "myexn" }
+ }
+}))
+
+
// Value conversion (Object.prototype.toValue)
function TestValueOf(handler) {
- var o = Proxy.create(handler)
- assertSame(o, Object.prototype.valueOf.call(o))
+ TestWithProxies(TestValueOf2, handler)
+}
+
+function TestValueOf2(handler, create) {
+ var p = create(handler)
+ assertSame(p, Object.prototype.valueOf.call(p))
}
TestValueOf({})
@@ -858,13 +1497,18 @@
// Enumerability (Object.prototype.propertyIsEnumerable)
var key
+
function TestIsEnumerable(handler) {
- var o = Proxy.create(handler)
- assertTrue(Object.prototype.propertyIsEnumerable.call(o, "a"))
+ TestWithProxies(TestIsEnumerable2, handler)
+}
+
+function TestIsEnumerable2(handler, create) {
+ var p = create(handler)
+ assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
assertEquals("a", key)
- assertTrue(Object.prototype.propertyIsEnumerable.call(o, 2))
+ assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
assertEquals("2", key)
- assertFalse(Object.prototype.propertyIsEnumerable.call(o, "z"))
+ assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
assertEquals("z", key)
}
@@ -896,3 +1540,143 @@
}
}
}))
+
+
+function TestIsEnumerableThrow(handler) {
+ TestWithProxies(TestIsEnumerableThrow2, handler)
+}
+
+function TestIsEnumerableThrow2(handler, create) {
+ var p = create(handler)
+ assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, "a") },
+ "myexn")
+ assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, 11) },
+ "myexn")
+}
+
+TestIsEnumerableThrow({
+ getOwnPropertyDescriptor: function(k) { throw "myexn" }
+})
+
+TestIsEnumerableThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return this.getOwnPropertyDescriptor2(k)
+ },
+ getOwnPropertyDescriptor2: function(k) { throw "myexn" }
+})
+
+TestIsEnumerableThrow({
+ getOwnPropertyDescriptor: function(k) {
+ return {get enumerable() { throw "myexn" }, configurable: true}
+ },
+})
+
+TestIsEnumerableThrow(Proxy.create({
+ get: function(pr, pk) { throw "myexn" }
+}))
+
+TestIsEnumerableThrow(Proxy.create({
+ get: function(pr, pk) {
+ return function(k) { throw "myexn" }
+ }
+}))
+
+
+
+// Calling (call, Function.prototype.call, Function.prototype.apply,
+// Function.prototype.bind).
+
+var global = this
+var receiver
+
+function TestCall(isStrict, callTrap) {
+ assertEquals(42, callTrap(5, 37))
+// TODO(rossberg): unrelated bug: this does not succeed for optimized code.
+// assertEquals(isStrict ? undefined : global, receiver)
+
+ var f = Proxy.createFunction({fix: function() { return {} }}, callTrap)
+ receiver = 333
+ assertEquals(42, f(11, 31))
+ assertEquals(isStrict ? undefined : global, receiver)
+ var o = {}
+ assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
+ assertEquals(o, receiver)
+ assertEquals(43, Function.prototype.call.call(f, null, 20, 23))
+ assertEquals(isStrict ? null : global, receiver)
+ assertEquals(44, Function.prototype.call.call(f, 2, 21, 23))
+ assertEquals(2, receiver.valueOf())
+ receiver = 333
+ assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
+ assertEquals(o, receiver)
+ var ff = Function.prototype.bind.call(f, o, 12)
+ receiver = 333
+ assertEquals(42, ff(30))
+ assertEquals(o, receiver)
+ receiver = 333
+ assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
+ assertEquals(o, receiver)
+
+ Object.freeze(f)
+ receiver = 333
+ assertEquals(42, f(11, 31))
+// TODO(rossberg): unrelated bug: this does not succeed for optimized code.
+// assertEquals(isStrict ? undefined : global, receiver)
+ receiver = 333
+ assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
+ assertEquals(o, receiver)
+ receiver = 333
+ assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
+ assertEquals(o, receiver)
+ receiver = 333
+ assertEquals(42, ff(30))
+ assertEquals(o, receiver)
+ receiver = 333
+ assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
+ assertEquals(o, receiver)
+}
+
+TestCall(false, function(x, y) {
+ receiver = this; return x + y
+})
+
+TestCall(true, function(x, y) {
+ "use strict";
+ receiver = this; return x + y
+})
+
+TestCall(false, Proxy.createFunction({}, function(x, y) {
+ receiver = this; return x + y
+}))
+
+TestCall(true, Proxy.createFunction({}, function(x, y) {
+ "use strict";
+ receiver = this; return x + y
+}))
+
+var p = Proxy.createFunction({fix: function() {return {}}}, function(x, y) {
+ receiver = this; return x + y
+})
+TestCall(false, p)
+Object.freeze(p)
+TestCall(false, p)
+
+
+function TestCallThrow(callTrap) {
+ var f = Proxy.createFunction({fix: function() {return {}}}, callTrap)
+ assertThrows(function(){ f(11) }, "myexn")
+ assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
+ assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
+
+ Object.freeze(f)
+ assertThrows(function(){ f(11) }, "myexn")
+ assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
+ assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
+}
+
+TestCallThrow(function() { throw "myexn" })
+TestCallThrow(Proxy.createFunction({}, function() { throw "myexn" }))
+
+var p = Proxy.createFunction(
+ {fix: function() {return {}}}, function() { throw "myexn" })
+Object.freeze(p)
+TestCallThrow(p)
diff --git a/test/mjsunit/harmony/weakmaps.js b/test/mjsunit/harmony/weakmaps.js
index e43f916..7b5dcaf 100644
--- a/test/mjsunit/harmony/weakmaps.js
+++ b/test/mjsunit/harmony/weakmaps.js
@@ -137,7 +137,11 @@
assertTrue(WeakMap.prototype.get instanceof Function)
assertTrue(WeakMap.prototype.has instanceof Function)
assertTrue(WeakMap.prototype.delete instanceof Function)
+
+
+// Regression test for WeakMap prototype.
assertTrue(WeakMap.prototype.constructor === WeakMap)
+assertTrue(Object.getPrototypeOf(WeakMap.prototype) === Object.prototype)
// Regression test for issue 1617: The prototype of the WeakMap constructor
diff --git a/test/mjsunit/html-string-funcs.js b/test/mjsunit/html-string-funcs.js
index 213b7f3..b640639 100644
--- a/test/mjsunit/html-string-funcs.js
+++ b/test/mjsunit/html-string-funcs.js
@@ -29,7 +29,7 @@
// HTML.
function CheckSimple(f, tag) {
assertEquals('<' + tag + '>foo</' + tag + '>',
- "foo"[f]().toLowerCase());
+ "foo"[f]().toLowerCase());
};
var simple = { big: 'big', blink: 'blink', bold: 'b',
fixed: 'tt', italics: 'i', small: 'small',
diff --git a/test/mjsunit/in.js b/test/mjsunit/in.js
index f98db42..cca6187 100644
--- a/test/mjsunit/in.js
+++ b/test/mjsunit/in.js
@@ -86,7 +86,7 @@
assertFalse(0 in a);
assertTrue(1 in a);
assertFalse(2 in a);
-assertFalse('0' in a);
+assertFalse('0' in a);
assertTrue('1' in a);
assertFalse('2' in a);
assertTrue('toString' in a, "toString");
diff --git a/test/mjsunit/instanceof.js b/test/mjsunit/instanceof.js
index 01ea426..050ef2d 100644
--- a/test/mjsunit/instanceof.js
+++ b/test/mjsunit/instanceof.js
@@ -60,10 +60,10 @@
function TestExceptions() {
function F() { }
- var items = [ 1, new Number(42),
- true,
+ var items = [ 1, new Number(42),
+ true,
'string', new String('hest'),
- {}, [],
+ {}, [],
F, new F(),
Object, String ];
diff --git a/test/mjsunit/keyed-storage-extend.js b/test/mjsunit/keyed-storage-extend.js
index 04d2f04..d7e157b 100644
--- a/test/mjsunit/keyed-storage-extend.js
+++ b/test/mjsunit/keyed-storage-extend.js
@@ -37,7 +37,7 @@
}
function GrowKeyed(o) {
- var names = ['a','b','c','d','e','f'];
+ var names = ['a','b','c','d','e','f'];
var i = 0;
o[names[i++]] = i;
o[names[i++]] = i;
diff --git a/test/mjsunit/mirror-array.js b/test/mjsunit/mirror-array.js
index eb8f72a..92e3913 100644
--- a/test/mjsunit/mirror-array.js
+++ b/test/mjsunit/mirror-array.js
@@ -64,7 +64,7 @@
assertTrue(mirror.protoObject() instanceof debug.Mirror, 'Unexpected mirror hierachy');
assertTrue(mirror.prototypeObject() instanceof debug.Mirror, 'Unexpected mirror hierachy');
assertEquals(mirror.length(), a.length, "Length mismatch");
-
+
var indexedProperties = mirror.indexedPropertiesFromRange();
assertEquals(indexedProperties.length, a.length);
for (var i = 0; i < indexedProperties.length; i++) {
@@ -110,7 +110,7 @@
var found = false;
for (var j = 0; j < fromJSON.properties.length; j++) {
if (names[i] == fromJSON.properties[j].name) {
- found = true;
+ found = true;
}
}
assertTrue(found, names[i])
diff --git a/test/mjsunit/mirror-function.js b/test/mjsunit/mirror-function.js
index 58aee3d..cda815d 100644
--- a/test/mjsunit/mirror-function.js
+++ b/test/mjsunit/mirror-function.js
@@ -65,7 +65,7 @@
assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror);
assertTrue(mirror.protoObject() instanceof debug.Mirror);
assertTrue(mirror.prototypeObject() instanceof debug.Mirror);
-
+
// Test text representation
assertEquals(f.toString(), mirror.toText());
diff --git a/test/mjsunit/mirror-script.js b/test/mjsunit/mirror-script.js
index 7156170..1d64ac2 100644
--- a/test/mjsunit/mirror-script.js
+++ b/test/mjsunit/mirror-script.js
@@ -62,7 +62,7 @@
if (eval_from_line) {
assertEquals(eval_from_line, mirror.evalFromLocation().line);
}
-
+
// Parse JSON representation and check.
var fromJSON = JSON.parse(json);
assertEquals('script', fromJSON.type);
diff --git a/test/mjsunit/mirror-unresolved-function.js b/test/mjsunit/mirror-unresolved-function.js
index c1fe4a3..46f22a0 100644
--- a/test/mjsunit/mirror-unresolved-function.js
+++ b/test/mjsunit/mirror-unresolved-function.js
@@ -64,7 +64,7 @@
assertEquals('undefined', mirror.constructorFunction().type());
assertEquals('undefined', mirror.protoObject().type());
assertEquals('undefined', mirror.prototypeObject().type());
-
+
// Parse JSON representation of unresolved functions and check.
var fromJSON = eval('(' + json + ')');
assertEquals('function', fromJSON.type, 'Unexpected mirror type in JSON');
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index b7b0c77..bae09b4 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -34,6 +34,10 @@
# Fails.
regress/regress-1119: FAIL
+#############################################################################
+# Fails due to r10102 which reverts precise stepping on the 3.6 branch.
+debug-step-2: FAIL
+
##############################################################################
# Too slow in debug mode with --stress-opt
compiler/regress-stacktrace-methods: PASS, SKIP if $mode == debug
@@ -115,6 +119,9 @@
##############################################################################
[ $arch == mips ]
+# Run those tests, but expect them to time out.
+array-sort: PASS || TIMEOUT
+mirror-object: PASS || TIMEOUT
# Skip long-running tests.
compiler/alloc-number: SKIP
@@ -141,8 +148,11 @@
regress/regress-create-exception: SKIP
regress/regress-3218915: SKIP
regress/regress-3247124: SKIP
+regress/regress-1132: SKIP
+regress/regress-1257: SKIP
+regress/regress-91008: SKIP
-
+##############################################################################
[ $isolates ]
# d8-os writes temporary files that might interfer with each other when running
# in multible threads. Skip this if running with isolates testing.
diff --git a/test/mjsunit/no-semicolon.js b/test/mjsunit/no-semicolon.js
index fa6ccba..273ec4b 100644
--- a/test/mjsunit/no-semicolon.js
+++ b/test/mjsunit/no-semicolon.js
@@ -30,7 +30,7 @@
function f() { return }
-function g() {
+function g() {
return
4;
}
@@ -42,4 +42,4 @@
assertEquals(0, i);
for (var i = 0; i < 10; i++) { continue }
-assertEquals(10, i);
\ No newline at end of file
+assertEquals(10, i);
diff --git a/test/mjsunit/object-define-properties.js b/test/mjsunit/object-define-properties.js
index 6b3725b..128df69 100644
--- a/test/mjsunit/object-define-properties.js
+++ b/test/mjsunit/object-define-properties.js
@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Tests the Object.defineProperties method - ES 15.2.3.7
-// Note that the internal DefineOwnProperty method is tested through
+// Note that the internal DefineOwnProperty method is tested through
// object-define-property.js, this file only contains tests specific for
// Object.defineProperties. Also note that object-create.js contains
// a range of indirect tests on this method since Object.create uses
diff --git a/test/mjsunit/object-literal-conversions.js b/test/mjsunit/object-literal-conversions.js
index 8540d93..742f814 100644
--- a/test/mjsunit/object-literal-conversions.js
+++ b/test/mjsunit/object-literal-conversions.js
@@ -43,4 +43,4 @@
assertEquals(7, test5[13]);
assertEquals(7, test6[17.31]);
-
\ No newline at end of file
+
diff --git a/test/mjsunit/object-literal-overwrite.js b/test/mjsunit/object-literal-overwrite.js
index 5c58a2d..5a3584d 100644
--- a/test/mjsunit/object-literal-overwrite.js
+++ b/test/mjsunit/object-literal-overwrite.js
@@ -79,7 +79,7 @@
// Test for the classic code generator.
function fun(x) {
- var inner = { j: function(x) { return x; }, j: 7 };
+ var inner = { j: function(x) { return x; }, j: 7 };
return inner.j;
}
@@ -115,4 +115,4 @@
var y = fun3();
assertEquals(7, y);
-assertEquals(3, glob3);
\ No newline at end of file
+assertEquals(3, glob3);
diff --git a/test/mjsunit/object-prevent-extensions.js b/test/mjsunit/object-prevent-extensions.js
index dc32342..322a2cb 100644
--- a/test/mjsunit/object-prevent-extensions.js
+++ b/test/mjsunit/object-prevent-extensions.js
@@ -33,7 +33,7 @@
assertTrue(Object.isExtensible(obj1));
Object.preventExtensions(obj1);
-// Make sure the is_extensible flag is set.
+// Make sure the is_extensible flag is set.
assertFalse(Object.isExtensible(obj1));
obj1.x = 42;
assertEquals(undefined, obj1.x);
diff --git a/test/mjsunit/regress/regress-1081309.js b/test/mjsunit/regress/regress-1081309.js
index 009ede1..5a6c524 100644
--- a/test/mjsunit/regress/regress-1081309.js
+++ b/test/mjsunit/regress/regress-1081309.js
@@ -67,7 +67,7 @@
// The expected backtrace is
// 1: g
// 0: [anonymous]
-
+
// Get the debug command processor.
var dcp = exec_state.debugCommandProcessor(false);
diff --git a/test/mjsunit/regress/regress-1092.js b/test/mjsunit/regress/regress-1092.js
index 0b29231..00422cb 100644
--- a/test/mjsunit/regress/regress-1092.js
+++ b/test/mjsunit/regress/regress-1092.js
@@ -25,7 +25,7 @@
// (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 CodeGenerator::EmitKeyedPropertyAssignment for the start
+// Test that CodeGenerator::EmitKeyedPropertyAssignment for the start
// of an initialization block doesn't normalize the properties of the
// JSGlobalProxy.
this.w = 0;
diff --git a/test/mjsunit/regress/regress-1110.js b/test/mjsunit/regress/regress-1110.js
index 204a87b..43b8d77 100644
--- a/test/mjsunit/regress/regress-1110.js
+++ b/test/mjsunit/regress/regress-1110.js
@@ -29,7 +29,7 @@
try {
function Crash() { continue;if (Crash) {
- } }
+ } }
Crash();
assertTrue(false);
} catch (e) {
diff --git a/test/mjsunit/regress/regress-1213575.js b/test/mjsunit/regress/regress-1213575.js
index 0c3dcc2..9d82064 100644
--- a/test/mjsunit/regress/regress-1213575.js
+++ b/test/mjsunit/regress/regress-1213575.js
@@ -33,7 +33,7 @@
var caught = false;
try {
- eval('const x');
+ eval('const x');
} catch(e) {
assertTrue(e instanceof TypeError);
caught = true;
diff --git a/test/mjsunit/regress/regress-98773.js b/test/mjsunit/regress/regress-1215.js
similarity index 82%
rename from test/mjsunit/regress/regress-98773.js
rename to test/mjsunit/regress/regress-1215.js
index eb24eb5..93a89f6 100644
--- a/test/mjsunit/regress/regress-98773.js
+++ b/test/mjsunit/regress/regress-1215.js
@@ -25,15 +25,12 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Calling Array.sort on an external array is not supposed to crash.
+// Make sure that the "message" property on Error.prototype
+// has the following descriptor:
+// {writable: true, enumerable: false, and configurable: true}
-var array = new Int16Array(23);
-array[7] = 7; array[9] = 9;
-assertEquals(23, array.length);
-assertEquals(7, array[7]);
-assertEquals(9, array[9]);
+var desc = Object.getOwnPropertyDescriptor(Error.prototype, 'message');
-Array.prototype.sort.call(array);
-assertEquals(23, array.length);
-assertEquals(7, array[21]);
-assertEquals(9, array[22]);
+assertEquals(desc.writable, true);
+assertEquals(desc.enumerable, false);
+assertEquals(desc.configurable, true);
diff --git a/test/mjsunit/regress/regress-1447.js b/test/mjsunit/regress/regress-1447.js
index 3c64929..2c1ee59 100644
--- a/test/mjsunit/regress/regress-1447.js
+++ b/test/mjsunit/regress/regress-1447.js
@@ -27,3 +27,11 @@
[0].forEach(function(){ Object.freeze(Array.prototype.forEach); });
[0].every(function(){ Object.seal(Array.prototype.every); });
+
+function testStrict(){
+ "use strict";
+ [0].forEach(function(){ Object.freeze(Array.prototype.forEach); });
+ [0].every(function(){ Object.seal(Array.prototype.every); });
+}
+
+testStrict();
diff --git a/test/mjsunit/regress/regress-98773.js b/test/mjsunit/regress/regress-1548.js
similarity index 67%
copy from test/mjsunit/regress/regress-98773.js
copy to test/mjsunit/regress/regress-1548.js
index eb24eb5..074007b 100644
--- a/test/mjsunit/regress/regress-98773.js
+++ b/test/mjsunit/regress/regress-1548.js
@@ -25,15 +25,24 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Calling Array.sort on an external array is not supposed to crash.
+// Test that the caller and arguments objects are not available on native
+// functions.
-var array = new Int16Array(23);
-array[7] = 7; array[9] = 9;
-assertEquals(23, array.length);
-assertEquals(7, array[7]);
-assertEquals(9, array[9]);
+function testfn(f) { return [1].map(f)[0]; }
+function foo() { return [].map.caller; }
+assertEquals(null, testfn(foo));
-Array.prototype.sort.call(array);
-assertEquals(23, array.length);
-assertEquals(7, array[21]);
-assertEquals(9, array[22]);
+// Try to delete the caller property (to make sure that we can't get to the
+// caller accessor on the prototype.
+delete Array.prototype.map.caller;
+assertEquals(null, testfn(foo));
+
+// Redo tests with arguments object.
+function testarguments(f) { return [1].map(f)[0]; }
+function bar() { return [].map.arguments; }
+assertEquals(null, testfn(bar));
+
+// Try to delete the arguments property (to make sure that we can't get to the
+// caller accessor on the prototype.
+delete Array.prototype.map.arguments;
+assertEquals(null, testarguments(bar));
diff --git a/test/mjsunit/regress/regress-1639.js b/test/mjsunit/regress/regress-1639.js
new file mode 100644
index 0000000..ed68c97
--- /dev/null
+++ b/test/mjsunit/regress/regress-1639.js
@@ -0,0 +1,85 @@
+// 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-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+var breaks = 0;
+
+function sendCommand(state, cmd) {
+ // Get the debug command processor in paused state.
+ var dcp = state.debugCommandProcessor(false);
+ var request = JSON.stringify(cmd);
+ var response = dcp.processDebugJSONRequest(request);
+}
+
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ var line = event_data.sourceLineText();
+ print('break: ' + line);
+
+ assertEquals(-1, line.indexOf('NOBREAK'),
+ "should not break on unexpected lines")
+ assertEquals('BREAK ' + breaks, line.substr(-7));
+ breaks++;
+ sendCommand(exec_state, {
+ seq: 0,
+ type: "request",
+ command: "continue",
+ arguments: { stepaction: "next" }
+ });
+ }
+ } catch (e) {
+ print(e);
+ }
+}
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+function a(f) {
+ if (f) { // NOBREAK: should not break here!
+ try {
+ f();
+ } catch(e) {
+ }
+ }
+} // BREAK 2
+
+function b() {
+ c(); // BREAK 0
+} // BREAK 1
+
+function c() {
+ a();
+}
+
+// Set a break point and call to invoke the debug event listener.
+Debug.setBreakPoint(b, 0, 0);
+a(b);
+// BREAK 3
diff --git a/test/mjsunit/regress/regress-1647.js b/test/mjsunit/regress/regress-1647.js
index ab6608c..a6afcc0 100644
--- a/test/mjsunit/regress/regress-1647.js
+++ b/test/mjsunit/regress/regress-1647.js
@@ -40,3 +40,4 @@
%OptimizeFunctionOnNextCall(f);
t.number = 2;
f();
+
diff --git a/test/mjsunit/regress/regress-1919169.js b/test/mjsunit/regress/regress-1919169.js
index 774f265..a732312 100644
--- a/test/mjsunit/regress/regress-1919169.js
+++ b/test/mjsunit/regress/regress-1919169.js
@@ -30,7 +30,7 @@
var s2 = "s2";
for (var i = 0; i < 2; i++) {
// Crashes in round i==1 with IllegalAccess in %StringAdd(x,y)
- var res = 1 + s2;
+ var res = 1 + s2;
s2 = 2;
}
}
diff --git a/test/mjsunit/regress/regress-20070207.js b/test/mjsunit/regress/regress-20070207.js
index e90b2ec..b7f7a5c 100644
--- a/test/mjsunit/regress/regress-20070207.js
+++ b/test/mjsunit/regress/regress-20070207.js
@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The following regression test illustrates a problem in using the
-// value of setting a property in the arguments object.
+// value of setting a property in the arguments object.
function f(s) {
arguments.length;
diff --git a/test/mjsunit/regress/regress-269.js b/test/mjsunit/regress/regress-269.js
index 49b24c0..ce165e0 100644
--- a/test/mjsunit/regress/regress-269.js
+++ b/test/mjsunit/regress/regress-269.js
@@ -40,10 +40,10 @@
function g() {
}
-
+
function f() {
debugger;
g.apply(null, ['']);
}
-f()
\ No newline at end of file
+f()
diff --git a/test/mjsunit/regress/regress-619.js b/test/mjsunit/regress/regress-619.js
index 24bdbc1..4d3e66b 100644
--- a/test/mjsunit/regress/regress-619.js
+++ b/test/mjsunit/regress/regress-619.js
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Tests that Object.defineProperty works correctly on array indices.
+// Tests that Object.defineProperty works correctly on array indices.
// Please see http://code.google.com/p/v8/issues/detail?id=619 for details.
var obj = {};
diff --git a/test/mjsunit/regress/regress-678525.js b/test/mjsunit/regress/regress-678525.js
index 5ff9c3d..11eaf74 100644
--- a/test/mjsunit/regress/regress-678525.js
+++ b/test/mjsunit/regress/regress-678525.js
@@ -36,16 +36,16 @@
assertEquals(56, '\8'.charCodeAt(0));
assertEquals('\010', '\10');
-assertEquals('\011', '\11');
+assertEquals('\011', '\11');
assertEquals('\012', '\12');
assertEquals('\013', '\13');
assertEquals('\014', '\14');
assertEquals('\015', '\15');
assertEquals('\016', '\16');
assertEquals('\017', '\17');
-
+
assertEquals('\020', '\20');
-assertEquals('\021', '\21');
+assertEquals('\021', '\21');
assertEquals('\022', '\22');
assertEquals('\023', '\23');
assertEquals('\024', '\24');
@@ -56,4 +56,4 @@
assertEquals(73, '\111'.charCodeAt(0));
assertEquals(105, '\151'.charCodeAt(0));
-
+
diff --git a/test/mjsunit/regress/regress-696.js b/test/mjsunit/regress/regress-696.js
index 21977e1..e443c42 100644
--- a/test/mjsunit/regress/regress-696.js
+++ b/test/mjsunit/regress/regress-696.js
@@ -28,7 +28,7 @@
// See: http://code.google.com/p/v8/issues/detail?id=696
// Because of the change in dateparser in revision 4557 to support time
// only strings in Date.parse we also misleadingly supported strings with non
-// leading numbers.
+// leading numbers.
assertTrue(isNaN(Date.parse('x')));
assertTrue(isNaN(Date.parse('1x')));
diff --git a/test/mjsunit/regress/regress-720.js b/test/mjsunit/regress/regress-720.js
index 97e1284..267b32d 100644
--- a/test/mjsunit/regress/regress-720.js
+++ b/test/mjsunit/regress/regress-720.js
@@ -27,7 +27,7 @@
// This regression test is used to ensure that Object.defineProperty
// keeps the existing value of the writable flag if none is given
-// in the provided descriptor.
+// in the provided descriptor.
// See: http://code.google.com/p/v8/issues/detail?id=720
var o = {x: 10};
diff --git a/test/mjsunit/regress/regress-747.js b/test/mjsunit/regress/regress-747.js
index 6fcc000..648c366 100644
--- a/test/mjsunit/regress/regress-747.js
+++ b/test/mjsunit/regress/regress-747.js
@@ -40,7 +40,7 @@
callEval();
} catch (e) {
assertUnreachable();
-}
+}
gc();
gc();
@@ -53,4 +53,4 @@
callEval();
} catch (e) {
assertUnreachable();
-}
+}
diff --git a/test/mjsunit/regress/regress-760-1.js b/test/mjsunit/regress/regress-760-1.js
index 2e0cee5..081c993 100644
--- a/test/mjsunit/regress/regress-760-1.js
+++ b/test/mjsunit/regress/regress-760-1.js
@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Check that when valueOf for a String object is overwritten it is called and
-// the result used when that object is added with a string.
+// the result used when that object is added with a string.
// See: http://code.google.com/p/v8/issues/detail?id=760
diff --git a/test/mjsunit/regress/regress-760-2.js b/test/mjsunit/regress/regress-760-2.js
index 1b1cbfe..549ed4e 100644
--- a/test/mjsunit/regress/regress-760-2.js
+++ b/test/mjsunit/regress/regress-760-2.js
@@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Check that when valueOf for a String object is overwritten it is called and
-// the result used when that object is added with a string.
+// the result used when that object is added with a string.
// See: http://code.google.com/p/v8/issues/detail?id=760
diff --git a/test/mjsunit/regress/regress-798.js b/test/mjsunit/regress/regress-798.js
index ffee5da..182eb4d 100644
--- a/test/mjsunit/regress/regress-798.js
+++ b/test/mjsunit/regress/regress-798.js
@@ -32,7 +32,7 @@
try {
y.x = 40;
} catch (e) {
- assertEquals(3, e.stack.split('\n').length);
+ assertEquals(3, e.stack.split('\n').length);
}
return 40;
});
@@ -41,7 +41,7 @@
try {
y.x = 40;
} catch(e) {
- assertEquals(3, e.stack.split('\n').length);
+ assertEquals(3, e.stack.split('\n').length);
}
});
@@ -50,7 +50,7 @@
try {
y.x = 30;
} catch (e) {
- assertEquals(3, e.stack.split('\n').length);
+ assertEquals(3, e.stack.split('\n').length);
}
return 30;
}
@@ -59,7 +59,7 @@
try {
y.x = 30;
} catch(e) {
- assertEquals(3, e.stack.split('\n').length);
+ assertEquals(3, e.stack.split('\n').length);
}
}
@@ -72,7 +72,7 @@
try {
y.x = 40;
} catch (e) {
- assertEquals(3, e.stack.split('\n').length);
+ assertEquals(3, e.stack.split('\n').length);
}
return 40;
},
@@ -80,7 +80,7 @@
try {
y.x = 40;
} catch(e) {
- assertEquals(3, e.stack.split('\n').length);
+ assertEquals(3, e.stack.split('\n').length);
}
}
}
@@ -88,7 +88,7 @@
Object.defineProperty(x, 'c', descriptor)
// Check that the stack for an exception in a getter and setter produce the
-// expected stack height.
+// expected stack height.
x.a;
x.b;
x.c;
diff --git a/test/mjsunit/regress/regress-918.js b/test/mjsunit/regress/regress-918.js
index 4b6ddba..871e9d9 100644
--- a/test/mjsunit/regress/regress-918.js
+++ b/test/mjsunit/regress/regress-918.js
@@ -28,6 +28,6 @@
// Parser should not accept parentheses around labels.
// See http://code.google.com/p/v8/issues/detail?id=918
-// The label was parsed as an expression and then tested for being a
+// The label was parsed as an expression and then tested for being a
// single identifier. This threw away the parentheses.
assertThrows("(label):42;");
diff --git a/test/mjsunit/regress/regress-925537.js b/test/mjsunit/regress/regress-925537.js
index 11582ea..d50c568 100644
--- a/test/mjsunit/regress/regress-925537.js
+++ b/test/mjsunit/regress/regress-925537.js
@@ -28,8 +28,8 @@
function assertClose(expected, actual) {
var delta = 0.00001;
if (Math.abs(expected - actual) > delta) {
- print('Failure: Expected <' + actual + '> to be close to <' +
- expected + '>');
+ print('Failure: Expected <' + actual + '> to be close to <' +
+ expected + '>');
}
}
diff --git a/test/mjsunit/regress/regress-937896.js b/test/mjsunit/regress/regress-937896.js
index e8e5ef2..e7831da 100644
--- a/test/mjsunit/regress/regress-937896.js
+++ b/test/mjsunit/regress/regress-937896.js
@@ -41,7 +41,7 @@
}
}
} catch (e) {
- // Empty.
+ // Empty.
}
return 42;
}
diff --git a/test/mjsunit/regress/regress-99167.js b/test/mjsunit/regress/regress-99167.js
deleted file mode 100644
index 5053ae5..0000000
--- a/test/mjsunit/regress/regress-99167.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --expose-gc --max-new-space-size=1024
-
-eval("function Node() { this.a = 1; this.a = 3; }");
-new Node;
-for (var i = 0; i < 4; ++i) gc();
-for (var i = 0; i < 100000; ++i) new Node;
diff --git a/test/mjsunit/regress/regress-98773.js b/test/mjsunit/regress/regress-bind-receiver.js
similarity index 70%
copy from test/mjsunit/regress/regress-98773.js
copy to test/mjsunit/regress/regress-bind-receiver.js
index eb24eb5..fc83a4e 100644
--- a/test/mjsunit/regress/regress-98773.js
+++ b/test/mjsunit/regress/regress-bind-receiver.js
@@ -25,15 +25,20 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Calling Array.sort on an external array is not supposed to crash.
+function strict() { 'use strict'; return this; }
+function lenient() { return this; }
+var obj = {};
-var array = new Int16Array(23);
-array[7] = 7; array[9] = 9;
-assertEquals(23, array.length);
-assertEquals(7, array[7]);
-assertEquals(9, array[9]);
+assertEquals(true, strict.bind(true)());
+assertEquals(42, strict.bind(42)());
+assertEquals("", strict.bind("")());
+assertEquals(null, strict.bind(null)());
+assertEquals(undefined, strict.bind(undefined)());
+assertEquals(obj, strict.bind(obj)());
-Array.prototype.sort.call(array);
-assertEquals(23, array.length);
-assertEquals(7, array[21]);
-assertEquals(9, array[22]);
+assertEquals(true, lenient.bind(true)() instanceof Boolean);
+assertEquals(true, lenient.bind(42)() instanceof Number);
+assertEquals(true, lenient.bind("")() instanceof String);
+assertEquals(this, lenient.bind(null)());
+assertEquals(this, lenient.bind(undefined)());
+assertEquals(obj, lenient.bind(obj)());
diff --git a/test/mjsunit/compiler/regress-96989.js b/test/mjsunit/regress/regress-fundecl.js
similarity index 83%
rename from test/mjsunit/compiler/regress-96989.js
rename to test/mjsunit/regress/regress-fundecl.js
index aedeb24..fddb589 100644
--- a/test/mjsunit/compiler/regress-96989.js
+++ b/test/mjsunit/regress/regress-fundecl.js
@@ -25,19 +25,20 @@
// (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
-// Test correct handling of uninitialized const.
+// Test hoisting of function declarations in the optimizing
+// compiler in case of deoptimization.
-function test() {
- for (var i = 41; i < 42; i++) {
- var c = t ^ i;
- }
- const t;
- return c;
+function h(a, b) {
+ var r = a + b;
+ function X() { return 42; }
+ return r + X();
}
-for (var i=0; i<10; i++) test();
-%OptimizeFunctionOnNextCall(test);
-assertEquals(41, test());
+for (var i = 0; i < 5; i++) h(1,2);
+
+%OptimizeFunctionOnNextCall(h);
+
+assertEquals(45, h(1,2));
+assertEquals("foo742", h("foo", 7));
diff --git a/test/mjsunit/setter-on-constructor-prototype.js b/test/mjsunit/setter-on-constructor-prototype.js
index d5718f9..a74f7da 100644
--- a/test/mjsunit/setter-on-constructor-prototype.js
+++ b/test/mjsunit/setter-on-constructor-prototype.js
@@ -35,14 +35,14 @@
if (ensure_fast_case) {
%ToFastProperties(C1.prototype);
}
-
+
for (var i = 0; i < 10; i++) {
var c1 = new C1();
assertEquals("undefined", typeof c1.x);
assertEquals(23, c1.y);
}
-
-
+
+
function C2() {
this.x = 23;
};
@@ -51,14 +51,14 @@
if (ensure_fast_case) {
%ToFastProperties(C2.prototype.__proto__)
}
-
+
for (var i = 0; i < 10; i++) {
var c2 = new C2();
assertEquals("undefined", typeof c2.x);
assertEquals(23, c2.y);
}
-
-
+
+
function C3() {
this.x = 23;
};
@@ -67,14 +67,14 @@
if (ensure_fast_case) {
%ToFastProperties(C3.prototype);
}
-
+
for (var i = 0; i < 10; i++) {
var c3 = new C3();
assertEquals("undefined", typeof c3.x);
assertEquals(23, c3.y);
}
-
-
+
+
function C4() {
this.x = 23;
};
@@ -84,14 +84,14 @@
if (ensure_fast_case) {
%ToFastProperties(C4.prototype.__proto__);
}
-
+
for (var i = 0; i < 10; i++) {
var c4 = new C4();
assertEquals("undefined", typeof c4.x);
assertEquals(23, c4.y);
}
-
-
+
+
function D() {
this.x = 23;
};
@@ -99,7 +99,7 @@
if (ensure_fast_case) {
%ToFastProperties(D.prototype);
}
-
+
for (var i = 0; i < 10; i++) {
var d = new D();
assertEquals(23, d.x);
diff --git a/test/mjsunit/string-compare-alignment.js b/test/mjsunit/string-compare-alignment.js
index a291417..0ae8eb7 100644
--- a/test/mjsunit/string-compare-alignment.js
+++ b/test/mjsunit/string-compare-alignment.js
@@ -29,8 +29,9 @@
// This situation can arise with sliced strings. This tests for an ARM bug
// that was fixed in r554.
-var base = "Now is the time for all good men to come to the aid of the party. " +
- "Now is the time for all good men to come to the aid of the party."
+var base =
+ "Now is the time for all good men to come to the aid of the party. " +
+ "Now is the time for all good men to come to the aid of the party."
var s1 = base.substring(0, 64);
var s2 = base.substring(66, 130);
diff --git a/test/mjsunit/string-indexof-1.js b/test/mjsunit/string-indexof-1.js
index c5ae4b8..db3623f 100644
--- a/test/mjsunit/string-indexof-1.js
+++ b/test/mjsunit/string-indexof-1.js
@@ -63,7 +63,7 @@
assertEquals(2, twoByteString.indexOf("\u03a3"), "First Sigma");
assertEquals(3, twoByteString.indexOf("\u03a3",3), "Second Sigma");
assertEquals(4, twoByteString.indexOf("\u0395"), "Epsilon");
-assertEquals(-1, twoByteString.indexOf("\u0392"), "Not beta");
+assertEquals(-1, twoByteString.indexOf("\u0392"), "Not beta");
// Test multi-char pattern
assertEquals(0, twoByteString.indexOf("\u039a\u0391"), "lambda Alpha");
@@ -71,7 +71,7 @@
assertEquals(2, twoByteString.indexOf("\u03a3\u03a3"), "Sigma Sigma");
assertEquals(3, twoByteString.indexOf("\u03a3\u0395"), "Sigma Epsilon");
-assertEquals(-1, twoByteString.indexOf("\u0391\u03a3\u0395"),
+assertEquals(-1, twoByteString.indexOf("\u0391\u03a3\u0395"),
"Not Alpha Sigma Epsilon");
//single char pattern
diff --git a/test/mjsunit/string-indexof-2.js b/test/mjsunit/string-indexof-2.js
index a7c3f60..48db84d 100644
--- a/test/mjsunit/string-indexof-2.js
+++ b/test/mjsunit/string-indexof-2.js
@@ -57,10 +57,10 @@
var index = -1;
do {
index = lipsum.indexOf(substring, index + 1);
- assertTrue(index != -1,
+ assertTrue(index != -1,
"Lipsum substring " + i + ".." + (i + len-1) + " not found");
- assertEquals(lipsum.substring(index, index + len), substring,
- "Wrong lipsum substring found: " + i + ".." + (i + len - 1) + "/" +
+ assertEquals(lipsum.substring(index, index + len), substring,
+ "Wrong lipsum substring found: " + i + ".." + (i + len - 1) + "/" +
index + ".." + (index + len - 1));
} while (index >= 0 && index < i);
assertEquals(i, index, "Lipsum match at " + i + ".." + (i + len - 1));
diff --git a/test/mjsunit/string-replace.js b/test/mjsunit/string-replace.js
index 9e4f559..6b022df 100644
--- a/test/mjsunit/string-replace.js
+++ b/test/mjsunit/string-replace.js
@@ -207,3 +207,8 @@
replaceTest("[ab-aabb-ab-b][az-aazz-az-z]",
"abaz", /a(.)/g, replacer);
+
+var str = 'She sells seashells by the seashore.';
+var re = /sh/g;
+assertEquals('She sells sea$schells by the sea$schore.',
+ str.replace(re,"$$" + 'sch'))
diff --git a/test/mjsunit/string-slices.js b/test/mjsunit/string-slices.js
index f629ca9..8cc1f81 100755
--- a/test/mjsunit/string-slices.js
+++ b/test/mjsunit/string-slices.js
@@ -57,7 +57,7 @@
assertEquals('abc', s.substr(-100, 3));
assertEquals(s1, s.substr(-s.length + 1));
-// assertEquals('', s.substr(0, void 0)); // smjs and rhino
+// assertEquals('', s.substr(0, void 0)); // smjs and rhino
assertEquals('abcdefghijklmn', s.substr(0, void 0)); // kjs and v8
assertEquals('', s.substr(0, null));
assertEquals(s, s.substr(0, String(s.length)));
@@ -196,4 +196,4 @@
assertEquals(a.slice(1,-1), b);
externalizeString(a);
assertEquals(a.slice(1,-1), b);
-*/
\ No newline at end of file
+*/
diff --git a/test/mjsunit/string-split.js b/test/mjsunit/string-split.js
index bc50945..d8412f0 100644
--- a/test/mjsunit/string-split.js
+++ b/test/mjsunit/string-split.js
@@ -68,13 +68,13 @@
/* "ab".split(/((?=.))/)
- *
+ *
* KJS: ,a,,b
* SM: a,,b,
* IE: a,b
* Opera: a,,b
* V8: a,,b
- *
+ *
* Opera seems to have this right. The others make no sense.
*/
assertArrayEquals(["a", "", "b"], "ab".split(/((?=.))/));
diff --git a/test/mjsunit/substr.js b/test/mjsunit/substr.js
index cffaf94..cab8b1b 100755
--- a/test/mjsunit/substr.js
+++ b/test/mjsunit/substr.js
@@ -55,7 +55,7 @@
assertEquals('abc', s.substr(-100, 3));
assertEquals(s1, s.substr(-s.length + 1));
-// assertEquals('', s.substr(0, void 0)); // smjs and rhino
+// assertEquals('', s.substr(0, void 0)); // smjs and rhino
assertEquals('abcdefghijklmn', s.substr(0, void 0)); // kjs and v8
assertEquals('', s.substr(0, null));
assertEquals(s, s.substr(0, String(s.length)));
diff --git a/test/mjsunit/this-property-assignment.js b/test/mjsunit/this-property-assignment.js
index c681999..54c6537 100644
--- a/test/mjsunit/this-property-assignment.js
+++ b/test/mjsunit/this-property-assignment.js
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Tests the handling of multiple assignments to the same property in a
+// Tests the handling of multiple assignments to the same property in a
// constructor that only has simple this property assignments.
function Node() {
diff --git a/test/mjsunit/try.js b/test/mjsunit/try.js
index 794860a..86afdf7 100644
--- a/test/mjsunit/try.js
+++ b/test/mjsunit/try.js
@@ -250,7 +250,7 @@
} catch (o) {
x--;
}
- }
+ }
return x;
}
@@ -274,7 +274,7 @@
x--;
}
x--; // should not happen
- }
+ }
return x;
}
diff --git a/test/mjsunit/unicode-test.js b/test/mjsunit/unicode-test.js
index 59a684e..66a029a 100644
--- a/test/mjsunit/unicode-test.js
+++ b/test/mjsunit/unicode-test.js
@@ -807,7 +807,7 @@
" * Васильев Л.С. Древний Китай: в 3 т. Т. 3. Период Чжаньго (V–III вв. до н.э.). М.: Восточная литература, 2006. ISBN 502018103X\n" +
" * Непомнин О.Е. История Китая: Эпоха Цин. XVII – начало XX века. М.: Восточная литература, 2005. ISBN 5020184004\n";
-var devanagari =
+var devanagari =
"भारत\n" +
"विकिपीडिया, एक मुक्त ज्ञानकोष से\n" +
"Jump to: navigation, search\n" +
@@ -1417,7 +1417,7 @@
"There are many words of French origin in English, such as competition, art, table, publicity, police, role, routine, machine, force, and many others that have been and are being anglicised; they are now pronounced according to English rules of phonology, rather than French. A large portion of English vocabulary is of French or Oïl language origin, most derived from, or transmitted via, the Anglo-Norman spoken by the upper classes in England for several hundred years after the Norman Conquest.\n";
-var greek =
+var greek =
"Ελλάδα\n" +
"Από τη Βικιπαίδεια, την ελεύθερη εγκυκλοπαίδεια\n" +
"Ελληνική Δημοκρατία\n" +
diff --git a/test/mjsunit/value-wrapper.js b/test/mjsunit/value-wrapper.js
index 88330b4..76e200f 100644
--- a/test/mjsunit/value-wrapper.js
+++ b/test/mjsunit/value-wrapper.js
@@ -39,7 +39,7 @@
assertEquals('object', (42).TypeOfThis());
assertEquals('object', (3.14).TypeOfThis());
}
-
+
for (var i = 0; i < 10; i++) {
assertEquals('object', 'xxx'['TypeOfThis']());
assertEquals('object', true['TypeOfThis']());
@@ -47,11 +47,11 @@
assertEquals('object', (42)['TypeOfThis']());
assertEquals('object', (3.14)['TypeOfThis']());
}
-
+
function CallTypeOfThis(obj) {
assertEquals('object', obj.TypeOfThis());
}
-
+
for (var i = 0; i < 10; i++) {
CallTypeOfThis('xxx');
CallTypeOfThis(true);
@@ -59,7 +59,7 @@
CallTypeOfThis(42);
CallTypeOfThis(3.14);
}
-
+
function TestWithWith(obj) {
with (obj) {
for (var i = 0; i < 10; i++) {
@@ -67,13 +67,13 @@
}
}
}
-
+
TestWithWith('xxx');
TestWithWith(true);
TestWithWith(false);
TestWithWith(42);
TestWithWith(3.14);
-
+
for (var i = 0; i < 10; i++) {
assertEquals('object', true[7]());
assertEquals('object', false[7]());
@@ -100,7 +100,7 @@
function TypeOfThis() { return typeof this; }
-// Test with normal setup of prototype.
+// Test with normal setup of prototype.
String.prototype.TypeOfThis = TypeOfThis;
Boolean.prototype.TypeOfThis = TypeOfThis;
Number.prototype.TypeOfThis = TypeOfThis;
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index f6d6925..3a27130 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -201,6 +201,10 @@
ecma_3/RegExp/regress-85721: PASS || FAIL if $mode == debug
+# Test that assumes specific execution time, flaky in debug mode.
+js1_5/Array/regress-101964: PASS || FAIL if $mode == debug
+
+
##################### INCOMPATIBLE TESTS #####################
# This section is for tests that fail in both V8 and JSC. Thus they
@@ -245,7 +249,7 @@
# toExponential argument restricted to range 0..20 in JSC/V8
ecma_3/Number/15.7.4.6-1: FAIL_OK
-#:=== RegExp:===
+#:=== RegExp:===
# We don't match the syntax error message of Mozilla for invalid
# RegExp flags.
ecma_3/RegExp/15.10.4.1-6: FAIL_OK
@@ -578,7 +582,7 @@
js1_5/Regress/regress-417893: FAIL_OK
-# Unsupported use of "[]" as function parameter. We match JSC.
+# Unsupported use of "[]" as function parameter. We match JSC.
js1_5/Regress/regress-416737-01: FAIL_OK
js1_5/Regress/regress-416737-02: FAIL_OK
diff --git a/test/preparser/duplicate-parameter.pyt b/test/preparser/duplicate-parameter.pyt
new file mode 100644
index 0000000..4dfb7d6
--- /dev/null
+++ b/test/preparser/duplicate-parameter.pyt
@@ -0,0 +1,90 @@
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Templatated tests with duplicate parameter names.
+
+# ----------------------------------------------------------------------
+# Constants and utility functions
+
+# A template that performs the same strict-mode test in different
+# scopes (global scope, function scope, and nested function scope),
+# and in non-strict mode too.
+def DuplicateParameterTest(name, source):
+ expectation = "strict_param_dupe"
+ non_selfstrict = {"selfstrict":"", "id":"selfnormal"}
+
+ Template(name, '"use strict";\n' + source)(non_selfstrict, expectation)
+ Template(name + '-infunc',
+ 'function foo() {\n "use strict";\n' + source +'\n}\n')(
+ non_selfstrict, expectation)
+ Template(name + '-infunc2',
+ 'function foo() {\n "use strict";\n function bar() {\n' +
+ source +'\n }\n}\n')(non_selfstrict, expectation)
+
+ selfstrict = {"selfstrict": "\"use strict\";", "id": "selfstrict"}
+ nestedstrict = {"selfstrict": "function bar(){\"use strict\";}",
+ "id": "nestedstrict"}
+ selfstrictnestedclean = {"selfstrict": """
+ "use strict";
+ function bar(){}
+ """, "id": "selfstrictnestedclean"}
+ selftest = Template(name + '-$id', source)
+ selftest(selfstrict, expectation)
+ selftest(selfstrictnestedclean, expectation)
+ selftest(nestedstrict, None)
+ selftest(non_selfstrict, None)
+
+
+# ----------------------------------------------------------------------
+# Test templates
+
+DuplicateParameterTest("dups", """
+ function foo(a, a) { $selfstrict }
+""");
+
+DuplicateParameterTest("dups-apart", """
+ function foo(a, b, c, d, e, f, g, h, i, j, k, l, m, n, a) { $selfstrict }
+""");
+
+DuplicateParameterTest("dups-escaped", """
+ function foo(\u0061, b, c, d, e, f, g, h, i, j, k, l, m, n, a) { $selfstrict }
+""");
+
+DuplicateParameterTest("triples", """
+ function foo(a, b, c, d, e, f, g, h, a, i, j, k, l, m, n, a) { $selfstrict }
+""");
+
+DuplicateParameterTest("escapes", """
+ function foo(a, \u0061) { $selfstrict }
+""");
+
+DuplicateParameterTest("long-names", """
+ function foo(arglebargleglopglyfarglebargleglopglyfarglebargleglopglyfa,
+ arglebargleglopglyfarglebargleglopglyfarglebargleglopglyfa) {
+ $selfstrict
+ }
+""");
diff --git a/test/preparser/duplicate-property.pyt b/test/preparser/duplicate-property.pyt
new file mode 100644
index 0000000..5abf9ad
--- /dev/null
+++ b/test/preparser/duplicate-property.pyt
@@ -0,0 +1,162 @@
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Tests of duplicate properties in object literals.
+
+# ----------------------------------------------------------------------
+# Utility functions to generate a number of tests for each property
+# name pair.
+
+def PropertyTest(name, propa, propb, allow_strict = True):
+ replacement = {"id1": propa, "id2": propb, "name": name}
+
+ # Tests same test in both strict and non-strict context.
+ def StrictTest(name, source, replacement, expectation):
+ if (allow_strict):
+ Template("strict-" + name,
+ "\"use strict\";\n" + source)(replacement, expectation)
+ Template(name, source)(replacement, expectation)
+
+ # This one only fails in non-strict context.
+ if (allow_strict):
+ Template("strict-$name-data-data", """
+ "use strict";
+ var o = {$id1: 42, $id2: 42};
+ """)(replacement, "strict_duplicate_property")
+
+ Template("$name-data-data", """
+ var o = {$id1: 42, $id2: 42};
+ """)(replacement, None)
+
+ StrictTest("$name-data-get", """
+ var o = {$id1: 42, get $id2(){}};
+ """, replacement, "accessor_data_property")
+
+ StrictTest("$name-data-set", """
+ var o = {$id1: 42, set $id2(v){}};
+ """, replacement, "accessor_data_property")
+
+ StrictTest("$name-get-data", """
+ var o = {get $id1(){}, $id2: 42};
+ """, replacement, "accessor_data_property")
+
+ StrictTest("$name-set-data", """
+ var o = {set $id1(v){}, $id2: 42};
+ """, replacement, "accessor_data_property")
+
+ StrictTest("$name-get-get", """
+ var o = {get $id1(){}, get $id2(){}};
+ """, replacement, "accessor_get_set")
+
+ StrictTest("$name-set-set", """
+ var o = {set $id1(v){}, set $id2(v){}};
+ """, replacement, "accessor_get_set")
+
+ StrictTest("$name-nested-get", """
+ var o = {get $id1(){}, o: {get $id2(){} } };
+ """, replacement, None)
+
+ StrictTest("$name-nested-set", """
+ var o = {set $id1(){}, o: {set $id2(){} } };
+ """, replacement, None)
+
+
+def TestBothWays(name, propa, propb, allow_strict = True):
+ PropertyTest(name + "-1", propa, propb, allow_strict)
+ PropertyTest(name + "-2", propb, propa, allow_strict)
+
+def TestSame(name, prop, allow_strict = True):
+ PropertyTest(name, prop, prop, allow_strict)
+
+#-----------------------------------------------------------------------
+
+# Simple identifier property
+TestSame("a", "a")
+
+# Get/set identifiers
+TestSame("get-id", "get")
+TestSame("set-id", "set")
+
+# Number properties
+TestSame("0", "0")
+TestSame("0.1", "0.1")
+TestSame("1.0", "1.0")
+TestSame("42.33", "42.33")
+TestSame("2^32-2", "4294967294")
+TestSame("2^32", "4294967296")
+TestSame("2^53", "9007199254740992")
+TestSame("Hex20", "0x20")
+TestSame("exp10", "1e10")
+TestSame("exp20", "1e20")
+TestSame("Oct40", "040", False);
+
+
+# String properties
+TestSame("str-a", '"a"')
+TestSame("str-0", '"0"')
+TestSame("str-42", '"42"')
+TestSame("str-empty", '""')
+
+# Keywords
+TestSame("if", "if")
+TestSame("case", "case")
+
+# Future reserved keywords
+TestSame("public", "public")
+TestSame("class", "class")
+
+
+# Test that numbers are converted to string correctly.
+
+TestBothWays("hex-int", "0x20", "32")
+TestBothWays("oct-int", "040", "32", False) # Octals disallowed in strict mode.
+TestBothWays("dec-int", "32.00", "32")
+TestBothWays("dec-underflow-int",
+ "32.00000000000000000000000000000000000000001", "32")
+TestBothWays("exp-int", "3.2e1", "32")
+TestBothWays("exp-int", "3200e-2", "32")
+TestBothWays("overflow-inf", "1e2000", "Infinity")
+TestBothWays("overflow-inf-exact", "1.797693134862315808e+308", "Infinity")
+TestBothWays("non-overflow-inf-exact", "1.797693134862315807e+308",
+ "1.7976931348623157e+308")
+TestBothWays("underflow-0", "1e-2000", "0")
+TestBothWays("underflow-0-exact", "2.4703282292062E-324", "0")
+TestBothWays("non-underflow-0-exact", "2.4703282292063E-324", "5e-324")
+TestBothWays("precission-loss-high", "9007199254740992", "9007199254740993")
+TestBothWays("precission-loss-low", "1.9999999999999998", "1.9999999999999997")
+TestBothWays("non-canonical-literal-int", "1.0", "1")
+TestBothWays("non-canonical-literal-frac", "1.50", "1.5")
+TestBothWays("rounding-down", "1.12512512512512452", "1.1251251251251244")
+TestBothWays("rounding-up", "1.12512512512512453", "1.1251251251251246")
+
+TestBothWays("hex-int-str", "0x20", '"32"')
+TestBothWays("dec-int-str", "32.00", '"32"')
+TestBothWays("exp-int-str", "3.2e1", '"32"')
+TestBothWays("overflow-inf-str", "1e2000", '"Infinity"')
+TestBothWays("underflow-0-str", "1e-2000", '"0"')
+TestBothWays("non-canonical-literal-int-str", "1.0", '"1"')
+TestBothWays("non-canonical-literal-frac-str", "1.50", '"1.5"')
diff --git a/test/preparser/testcfg.py b/test/preparser/testcfg.py
index d900e26..88c06a3 100644
--- a/test/preparser/testcfg.py
+++ b/test/preparser/testcfg.py
@@ -98,7 +98,6 @@
def ParsePythonTestTemplates(self, result, filename,
executable, current_path, mode):
pathname = join(self.root, filename + ".pyt")
- source = open(pathname).read();
def Test(name, source, expectation):
throws = None
if (expectation is not None):
@@ -118,8 +117,7 @@
testsource = testsource.replace("$"+key, replacement[key]);
Test(testname, testsource, expectation)
return MkTest
- eval(compile(source, pathname, "exec"),
- {"Test": Test, "Template": Template}, {})
+ execfile(pathname, {"Test": Test, "Template": Template})
def ListTests(self, current_path, path, mode, variant_flags):
executable = 'preparser'
@@ -148,7 +146,7 @@
filenames.sort()
for file in filenames:
# Each file as a python source file to be executed in a specially
- # perparsed environment (defining the Template and Test functions)
+ # created environment (defining the Template and Test functions)
self.ParsePythonTestTemplates(result, file,
executable, current_path, mode)
return result
diff --git a/tools/codemap.js b/tools/codemap.js
index dec494a..129179e 100644
--- a/tools/codemap.js
+++ b/tools/codemap.js
@@ -79,6 +79,7 @@
* @param {CodeMap.CodeEntry} codeEntry Code entry object.
*/
CodeMap.prototype.addCode = function(start, codeEntry) {
+ this.deleteAllCoveredNodes_(this.dynamics_, start, start + codeEntry.size);
this.dynamics_.insert(start, codeEntry);
};
@@ -92,6 +93,7 @@
*/
CodeMap.prototype.moveCode = function(from, to) {
var removedNode = this.dynamics_.remove(from);
+ this.deleteAllCoveredNodes_(this.dynamics_, to, to + removedNode.value.size);
this.dynamics_.insert(to, removedNode.value);
};
@@ -146,6 +148,23 @@
/**
* @private
*/
+CodeMap.prototype.deleteAllCoveredNodes_ = function(tree, start, end) {
+ var to_delete = [];
+ var addr = end - 1;
+ while (addr >= start) {
+ var node = tree.findGreatestLessThan(addr);
+ if (!node) break;
+ var start2 = node.key, end2 = start2 + node.value.size;
+ if (start2 < end && start < end2) to_delete.push(start2);
+ addr = start2 - 1;
+ }
+ for (var i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
+};
+
+
+/**
+ * @private
+ */
CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) {
return addr >= node.key && addr < (node.key + node.value.size);
};
diff --git a/tools/gdb-v8-support.py b/tools/gdb-v8-support.py
index 0aa1d49..9cc046c 100644
--- a/tools/gdb-v8-support.py
+++ b/tools/gdb-v8-support.py
@@ -138,7 +138,7 @@
else:
return '?'
-
+
def v8_get_value(vstring):
v = gdb.parse_and_eval(vstring)
return v8_to_int(v)
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 2da8213..5014417 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -71,6 +71,13 @@
],
},
}],
+ ['soname_version!=""', {
+ # Ideally, we'd like to specify the full filename for the
+ # library and set it to "libv8.so.<(soname_version)",
+ # but currently the best we can do is use 'product_name' and
+ # get "libv8-<(soname_version).so".
+ 'product_name': 'v8-<(soname_version)',
+ }],
],
},
{
@@ -288,11 +295,11 @@
'../../src/disasm.h',
'../../src/disassembler.cc',
'../../src/disassembler.h',
- '../../src/dtoa.cc',
- '../../src/dtoa.h',
'../../src/diy-fp.cc',
'../../src/diy-fp.h',
'../../src/double.h',
+ '../../src/dtoa.cc',
+ '../../src/dtoa.h',
'../../src/elements.cc',
'../../src/elements.h',
'../../src/execution.cc',
@@ -407,10 +414,10 @@
'../../src/runtime-profiler.h',
'../../src/safepoint-table.cc',
'../../src/safepoint-table.h',
- '../../src/scanner-base.cc',
- '../../src/scanner-base.h',
'../../src/scanner.cc',
'../../src/scanner.h',
+ '../../src/scanner-character-streams.cc',
+ '../../src/scanner-character-streams.h',
'../../src/scopeinfo.cc',
'../../src/scopeinfo.h',
'../../src/scopes.cc',
@@ -418,7 +425,7 @@
'../../src/serialize.cc',
'../../src/serialize.h',
'../../src/small-pointer-list.h',
- '../../src/smart-pointer.h',
+ '../../src/smart-array-pointer.h',
'../../src/snapshot-common.cc',
'../../src/snapshot.h',
'../../src/spaces-inl.h',
@@ -643,6 +650,8 @@
['OS=="win"', {
'sources': [
'../../src/platform-win32.cc',
+ '../../src/win32-math.cc',
+ '../../src/win32-math.h',
],
'msvs_disabled_warnings': [4351, 4355, 4800],
'link_settings': {
@@ -787,19 +796,61 @@
'../../src',
],
'sources': [
+ '../../include/v8-preparser.h',
+ '../../include/v8stdint.h',
'../../src/allocation.cc',
+ '../../src/allocation.h',
'../../src/bignum.cc',
+ '../../src/bignum.h',
+ '../../src/bignum-dtoa.cc',
+ '../../src/bignum-dtoa.h',
'../../src/cached-powers.cc',
+ '../../src/cached-powers.h',
+ '../../src/char-predicates-inl.h',
+ '../../src/char-predicates.h',
+ '../../src/checks.h',
+ '../../src/conversions-inl.h',
'../../src/conversions.cc',
+ '../../src/conversions.h',
+ '../../src/diy-fp.cc',
+ '../../src/diy-fp.h',
+ '../../src/double.h',
+ '../../src/dtoa.cc',
+ '../../src/dtoa.h',
+ '../../src/fast-dtoa.cc',
+ '../../src/fast-dtoa.h',
+ '../../src/fixed-dtoa.cc',
+ '../../src/fixed-dtoa.h',
+ '../../src/globals.h',
'../../src/hashmap.cc',
+ '../../src/hashmap.h',
+ '../../src/list-inl.h',
+ '../../src/list.h',
+ '../../src/preparse-data-format.h',
'../../src/preparse-data.cc',
+ '../../src/preparse-data.h',
'../../src/preparser.cc',
+ '../../src/preparser.h',
'../../src/preparser-api.cc',
- '../../src/scanner-base.cc',
+ '../../src/scanner.cc',
+ '../../src/scanner.h',
'../../src/strtod.cc',
+ '../../src/strtod.h',
'../../src/token.cc',
+ '../../src/token.h',
+ '../../src/unicode-inl.h',
'../../src/unicode.cc',
+ '../../src/unicode.h',
+ '../../src/utils-inl.h',
'../../src/utils.cc',
+ '../../src/utils.h',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'sources': [
+ '../../src/win32-math.cc',
+ '../../src/win32-math.h',
+ ]}],
],
},
],
diff --git a/tools/presubmit.py b/tools/presubmit.py
index c191fc7..fda7ba9 100755
--- a/tools/presubmit.py
+++ b/tools/presubmit.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2008 the V8 project authors. All rights reserved.
+# Copyright 2011 the V8 project authors. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
@@ -42,6 +42,7 @@
import re
import sys
import subprocess
+from subprocess import PIPE
# Disabled LINT rules and reason.
# build/include_what_you_use: Started giving false positives for variables
@@ -88,7 +89,6 @@
whitespace/braces
whitespace/comma
whitespace/comments
-whitespace/end_of_line
whitespace/ending_newline
whitespace/indent
whitespace/labels
@@ -231,11 +231,29 @@
class SourceProcessor(SourceFileProcessor):
"""
- Check that all files include a copyright notice.
+ Check that all files include a copyright notice and no trailing whitespaces.
"""
RELEVANT_EXTENSIONS = ['.js', '.cc', '.h', '.py', '.c', 'SConscript',
- 'SConstruct', '.status']
+ 'SConstruct', '.status', '.gyp', '.gypi']
+
+ # Overwriting the one in the parent class.
+ def FindFilesIn(self, path):
+ if os.path.exists(path+'/.git'):
+ output = subprocess.Popen('git ls-files --full-name',
+ stdout=PIPE, cwd=path, shell=True)
+ result = []
+ for file in output.stdout.read().split():
+ for dir_part in os.path.dirname(file).split(os.sep):
+ if self.IgnoreDir(dir_part):
+ break
+ else:
+ if self.IsRelevant(file) and not self.IgnoreFile(file):
+ result.append(join(path, file))
+ if output.wait() == 0:
+ return result
+ return super(SourceProcessor, self).FindFilesIn(path)
+
def IsRelevant(self, name):
for ext in SourceProcessor.RELEVANT_EXTENSIONS:
if name.endswith(ext):
@@ -273,17 +291,37 @@
if not COPYRIGHT_HEADER_PATTERN.search(contents):
print "%s is missing a correct copyright header." % name
result = False
+ ext = base.split('.').pop()
+ if ' \n' in contents or contents.endswith(' '):
+ line = 0
+ lines = []
+ parts = contents.split(' \n')
+ if not contents.endswith(' '):
+ parts.pop()
+ for part in parts:
+ line += part.count('\n') + 1
+ lines.append(str(line))
+ linenumbers = ', '.join(lines)
+ if len(lines) > 1:
+ print "%s has trailing whitespaces in lines %s." % (name, linenumbers)
+ else:
+ print "%s has trailing whitespaces in line %s." % (name, linenumbers)
+ result = False
return result
def ProcessFiles(self, files, path):
success = True
+ violations = 0
for file in files:
try:
handle = open(file)
contents = handle.read()
- success = self.ProcessContents(file, contents) and success
+ if not self.ProcessContents(file, contents):
+ success = False
+ violations += 1
finally:
handle.close()
+ print "Total violating files: %s" % violations
return success
@@ -299,8 +337,10 @@
parser = GetOptions()
(options, args) = parser.parse_args()
success = True
+ print "Running C++ lint check..."
if not options.no_lint:
success = CppLintProcessor().Run(workspace) and success
+ print "Running copyright header and trailing whitespaces check..."
success = SourceProcessor().Run(workspace) and success
if success:
return 0
diff --git a/tools/process-heap-prof.py b/tools/process-heap-prof.py
index 6a2c397..a26cbf1 100755
--- a/tools/process-heap-prof.py
+++ b/tools/process-heap-prof.py
@@ -47,7 +47,7 @@
itemname = 'heap-js-cons-item'
else:
itemname = 'heap-sample-item'
-
+
first_call_time = None
sample_time = 0.0
sampling = False
@@ -108,11 +108,11 @@
if not ProcessOptions(options):
parser.print_help()
sys.exit();
-
+
if not args:
print "Missing logfile"
sys.exit();
-
+
ProcessLogFile(args[0], options)
diff --git a/tools/push-to-trunk.sh b/tools/push-to-trunk.sh
new file mode 100755
index 0000000..761b733
--- /dev/null
+++ b/tools/push-to-trunk.sh
@@ -0,0 +1,431 @@
+#!/bin/bash
+# Copyright 2011 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+########## Global variable definitions
+
+BRANCHNAME=prepare-push
+TRUNKBRANCH=trunk-push
+TEMP_BRANCH=v8-push-to-trunk-script-temporary-branch
+VERSION_FILE="src/version.cc"
+PERSISTFILE_BASENAME=/tmp/v8-push-to-trunk-tempfile
+CHANGELOG_ENTRY_FILE="$PERSISTFILE_BASENAME-changelog-entry"
+PATCH_FILE="$PERSISTFILE_BASENAME-patch"
+COMMITMSG_FILE="$PERSISTFILE_BASENAME-commitmsg"
+TOUCHED_FILES_FILE="$PERSISTFILE_BASENAME-touched-files"
+STEP=0
+
+
+########## Function definitions
+
+usage() {
+cat << EOF
+usage: $0 OPTIONS
+
+Performs the necessary steps for a V8 push to trunk. Only works for \
+git checkouts.
+
+OPTIONS:
+ -h Show this message
+ -s Specify the step where to start work. Default: 0.
+ -l Manually specify the git commit ID of the last push to trunk.
+EOF
+}
+
+die() {
+ [[ -n "$1" ]] && echo "Error: $1"
+ echo "Exiting."
+ exit 1
+}
+
+confirm() {
+ echo -n "$1 [Y/n] "
+ read ANSWER
+ if [[ -z "$ANSWER" || "$ANSWER" == "Y" || "$ANSWER" == "y" ]] ; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+delete_branch() {
+ local MATCH=$(git branch | grep $1 | awk '{print $NF}' )
+ if [ "$MATCH" == "$1" ] ; then
+ confirm "Branch $1 exists, do you want to delete it?"
+ if [ $? -eq 0 ] ; then
+ git branch -D $1 || die "Deleting branch '$1' failed."
+ echo "Branch $1 deleted."
+ else
+ die "Can't continue. Please delete branch $1 and try again."
+ fi
+ fi
+}
+
+# Persist and restore variables to support canceling/resuming execution
+# of this script.
+persist() {
+ local VARNAME=$1
+ local FILE="$PERSISTFILE_BASENAME-$VARNAME"
+ echo "${!VARNAME}" > $FILE
+}
+
+restore() {
+ local VARNAME=$1
+ local FILE="$PERSISTFILE_BASENAME-$VARNAME"
+ local VALUE="$(cat $FILE)"
+ eval "$VARNAME=\"$VALUE\""
+}
+
+restore_if_unset() {
+ local VARNAME=$1
+ [[ -z "${!VARNAME}" ]] && restore "$VARNAME"
+ [[ -z "${!VARNAME}" ]] && die "Variable '$VARNAME' could not be restored."
+}
+
+
+########## Option parsing
+
+while getopts ":hs:l:" OPTION ; do
+ case $OPTION in
+ h) usage
+ exit 0
+ ;;
+ s) STEP=$OPTARG
+ ;;
+ l) LASTPUSH=$OPTARG
+ ;;
+ ?) echo "Illegal option: -$OPTARG"
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+
+########## Regular workflow
+
+# Cancel if this is not a git checkout.
+[[ -d .git ]] \
+ || die "This is not a git checkout, this script won't work for you."
+
+# Cancel if EDITOR is unset or not executable.
+[[ -n "$EDITOR" && -x "$(which $EDITOR)" ]] \
+ || die "Please set your EDITOR environment variable, you'll need it."
+
+if [ $STEP -le 0 ] ; then
+ echo ">>> Step 0: Preparation"
+ # Check for a clean workdir.
+ [[ -z "$(git status -s -uno)" ]] \
+ || die "Workspace is not clean. Please commit or undo your changes."
+
+ # Persist current branch.
+ CURRENT_BRANCH=$(git status -s -b -uno | grep "^##" | awk '{print $2}')
+ persist "CURRENT_BRANCH"
+ # Get ahold of a safe temporary branch and check it out.
+ if [ "$CURRENT_BRANCH" != "$TEMP_BRANCH" ] ; then
+ delete_branch $TEMP_BRANCH
+ git checkout -b $TEMP_BRANCH
+ fi
+ # Delete branches if they exist.
+ delete_branch $BRANCHNAME
+ delete_branch $TRUNKBRANCH
+fi
+
+if [ $STEP -le 1 ] ; then
+ echo ">>> Step 1: Fetch unfetched revisions."
+ git svn fetch || die "'git svn fetch' failed."
+fi
+
+if [ $STEP -le 2 ] ; then
+ echo ">>> Step 2: Create a fresh branch."
+ git checkout -b $BRANCHNAME svn/bleeding_edge \
+ || die "Creating branch $BRANCHNAME failed."
+fi
+
+if [ $STEP -le 3 ] ; then
+ echo ">>> Step 3: Detect commit ID of last push to trunk."
+ [[ -n "$LASTPUSH" ]] || LASTPUSH=$(git log -1 --format=%H ChangeLog)
+ LOOP=1
+ while [ $LOOP -eq 1 ] ; do
+ # Print assumed commit, circumventing git's pager.
+ git log -1 $LASTPUSH | cat
+ confirm "Is the commit printed above the last push to trunk?"
+ if [ $? -eq 0 ] ; then
+ LOOP=0
+ else
+ LASTPUSH=$(git log -1 --format=%H $LASTPUSH^ ChangeLog)
+ fi
+ done
+ persist "LASTPUSH"
+fi
+
+if [ $STEP -le 4 ] ; then
+ echo ">>> Step 4: Prepare raw ChangeLog entry."
+# These version numbers are used again later for the trunk commit.
+ MAJOR=$(grep "#define MAJOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
+ persist "MAJOR"
+ MINOR=$(grep "#define MINOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
+ persist "MINOR"
+ BUILD=$(grep "#define BUILD_NUMBER" "$VERSION_FILE" | awk '{print $NF}')
+ persist "BUILD"
+
+ DATE=$(date +%Y-%m-%d)
+ persist "DATE"
+ echo "$DATE: Version $MAJOR.$MINOR.$BUILD" > "$CHANGELOG_ENTRY_FILE"
+ echo "" >> "$CHANGELOG_ENTRY_FILE"
+ COMMITS=$(git log $LASTPUSH..HEAD --format=%H)
+ for commit in $COMMITS ; do
+ # Get the commit's title line.
+ git log -1 $commit --format="%w(80,8,8)%s" >> "$CHANGELOG_ENTRY_FILE"
+ # Grep for "BUG=xxxx" lines in the commit message.
+ git log -1 $commit --format="%b" | grep BUG= | grep -v "BUG=$" \
+ | sed -e 's/^/ /' \
+ >> "$CHANGELOG_ENTRY_FILE"
+ # Append the commit's author for reference.
+ git log -1 $commit --format="%w(80,8,8)(%an)" >> "$CHANGELOG_ENTRY_FILE"
+ echo "" >> "$CHANGELOG_ENTRY_FILE"
+ done
+fi
+
+if [ $STEP -le 5 ] ; then
+ echo ">>> Step 5: Edit ChangeLog entry."
+ echo -n "Please press <Return> to have your EDITOR open the ChangeLog entry, \
+then edit its contents to your liking. When you're done, save the file and \
+exit your EDITOR. "
+ read ANSWER
+ $EDITOR "$CHANGELOG_ENTRY_FILE"
+ NEWCHANGELOG=$(mktemp)
+ # Eliminate any trailing newlines by going through a shell variable.
+ CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE")
+ [[ -n "$CHANGELOGENTRY" ]] || die "Empty ChangeLog entry."
+ echo "$CHANGELOGENTRY" > "$NEWCHANGELOG"
+ echo "" >> "$NEWCHANGELOG" # Explicitly insert two empty lines.
+ echo "" >> "$NEWCHANGELOG"
+ cat ChangeLog >> "$NEWCHANGELOG"
+ mv "$NEWCHANGELOG" ChangeLog
+fi
+
+if [ $STEP -le 6 ] ; then
+ echo ">>> Step 6: Increment version number."
+ restore_if_unset "BUILD"
+ NEWBUILD=$(($BUILD + 1))
+ confirm "Automatically increment BUILD_NUMBER? (Saying 'n' will fire up \
+your EDITOR on $VERSION_FILE so you can make arbitrary changes. When \
+you're done, save the file and exit your EDITOR.)"
+ if [ $? -eq 0 ] ; then
+ sed -e "/#define BUILD_NUMBER/s/[0-9]*$/$NEWBUILD/" \
+ -i "$VERSION_FILE"
+ else
+ $EDITOR "$VERSION_FILE"
+ fi
+ NEWMAJOR=$(grep "#define MAJOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
+ persist "NEWMAJOR"
+ NEWMINOR=$(grep "#define MINOR_VERSION" "$VERSION_FILE" | awk '{print $NF}')
+ persist "NEWMINOR"
+ NEWBUILD=$(grep "#define BUILD_NUMBER" "$VERSION_FILE" | awk '{print $NF}')
+ persist "NEWBUILD"
+fi
+
+if [ $STEP -le 7 ] ; then
+ echo ">>> Step 7: Commit to local branch."
+ restore_if_unset "NEWMAJOR"
+ restore_if_unset "NEWMINOR"
+ restore_if_unset "NEWBUILD"
+ git commit -a -m "Prepare push to trunk. \
+Now working on version $NEWMAJOR.$NEWMINOR.$NEWBUILD." \
+ || die "'git commit -a' failed."
+fi
+
+if [ $STEP -le 8 ] ; then
+ echo ">>> Step 8: Upload for code review."
+ echo -n "Please enter the email address of a V8 reviewer for your patch: "
+ read REVIEWER
+ git cl upload -r $REVIEWER --send-mail \
+ || die "'git cl upload' failed, please try again."
+fi
+
+if [ $STEP -le 9 ] ; then
+ echo ">>> Step 9: Commit to the repository."
+ echo "Please wait for an LGTM, then type \"LGTM<Return>\" to commit your \
+change. (If you need to iterate on the patch, do so in another shell.)"
+ unset ANSWER
+ while [ "$ANSWER" != "LGTM" ] ; do
+ [[ -n "$ANSWER" ]] && echo "That was not 'LGTM'."
+ echo -n "> "
+ read ANSWER
+ done
+ # Re-read the ChangeLog entry (to pick up possible changes).
+ cat ChangeLog | awk --posix '{
+ if ($0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}:/) {
+ if (in_firstblock == 1) {
+ exit 0;
+ } else {
+ in_firstblock = 1;
+ }
+ };
+ print $0;
+ }' > "$CHANGELOG_ENTRY_FILE"
+ git cl dcommit || die "'git cl dcommit' failed, please try again."
+fi
+
+if [ $STEP -le 10 ] ; then
+ echo ">>> Step 10: NOP"
+ # Present in the manual guide, not necessary (even harmful!) for this script.
+fi
+
+if [ $STEP -le 11 ] ; then
+ echo ">>> Step 11: Squash commits into one."
+ # Instead of relying on "git rebase -i", we'll just create a diff, because
+ # that's easier to automate.
+ git diff svn/trunk > "$PATCH_FILE"
+ # Convert the ChangeLog entry to commit message format:
+ # - remove date
+ # - remove indentation
+ # - merge paragraphs into single long lines, keeping empty lines between them.
+ restore_if_unset "DATE"
+ CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE")
+ echo "$CHANGELOGENTRY" \
+ | sed -e "s/^$DATE: //" \
+ | sed -e 's/^ *//' \
+ | awk '{
+ if (need_space == 1) {
+ printf(" ");
+ };
+ printf("%s", $0);
+ if ($0 ~ /^$/) {
+ printf("\n\n");
+ need_space = 0;
+ } else {
+ need_space = 1;
+ }
+ }' > "$COMMITMSG_FILE" || die "Commit message editing failed."
+ LOOP=1
+ while [ $LOOP -eq 1 ] ; do
+ echo "This is the trunk commit message:"
+ echo "--------------------"
+ cat "$COMMITMSG_FILE"
+ echo -e "\n--------------------"
+ confirm "Does this look good to you? (Saying 'n' will fire up your \
+EDITOR so you can change the commit message. When you're done, save the \
+file and exit your EDITOR.)"
+ if [ $? -eq 0 ] ; then
+ LOOP=0
+ else
+ $EDITOR "$COMMITMSG_FILE"
+ fi
+ done
+ rm -f "$CHANGELOG_ENTRY_FILE"
+fi
+
+if [ $STEP -le 12 ] ; then
+ echo ">>> Step 12: Create a new branch from trunk."
+ git checkout -b $TRUNKBRANCH svn/trunk \
+ || die "Checking out a new branch '$TRUNKBRANCH' failed."
+fi
+
+if [ $STEP -le 13 ] ; then
+ echo ">>> Step 13: Apply squashed changes."
+ patch -p1 < "$PATCH_FILE" | tee >(awk '{print $NF}' >> "$TOUCHED_FILES_FILE")
+ [[ $? -eq 0 ]] || die "Applying the patch to trunk failed."
+ # Stage added and modified files.
+ TOUCHED_FILES=$(cat "$TOUCHED_FILES_FILE")
+ for FILE in $TOUCHED_FILES ; do
+ git add "$FILE"
+ done
+ # Stage deleted files.
+ DELETED_FILES=$(git status -s -uno --porcelain | grep "^ D" \
+ | awk '{print $NF}')
+ for FILE in $DELETED_FILES ; do
+ git rm "$FILE"
+ done
+ rm -f "$PATCH_FILE"
+ rm -f "$TOUCHED_FILES_FILE"
+fi
+
+if [ $STEP -le 14 ] ; then
+ echo ">>> Step 14: Set correct version for trunk."
+ restore_if_unset "MAJOR"
+ restore_if_unset "MINOR"
+ restore_if_unset "BUILD"
+ sed -e "/#define MAJOR_VERSION/s/[0-9]*$/$MAJOR/" \
+ -e "/#define MINOR_VERSION/s/[0-9]*$/$MINOR/" \
+ -e "/#define BUILD_NUMBER/s/[0-9]*$/$BUILD/" \
+ -e "/#define PATCH_LEVEL/s/[0-9]*$/0/" \
+ -e "/#define IS_CANDIDATE_VERSION/s/[0-9]*$/0/" \
+ -i "$VERSION_FILE" || die "Patching $VERSION_FILE failed."
+fi
+
+if [ $STEP -le 15 ] ; then
+ echo ">>> Step 15: Commit to local trunk branch."
+ git add "$VERSION_FILE"
+ git commit -F "$COMMITMSG_FILE" || die "'git commit' failed."
+ rm -f "$COMMITMSG_FILE"
+fi
+
+if [ $STEP -le 16 ] ; then
+ echo ">>> Step 16: Sanity check."
+ confirm "Please check if your local checkout is sane: Inspect $VERSION_FILE, \
+compile, run tests. Do you want to commit this new trunk revision to the \
+repository?"
+ [[ $? -eq 0 ]] || die "Execution canceled."
+fi
+
+if [ $STEP -le 17 ] ; then
+ echo ">>> Step 17. Commit to SVN."
+ git svn dcommit || die "'git svn dcommit' failed."
+fi
+
+if [ $STEP -le 18 ] ; then
+ echo ">>> Step 18: Tag the new revision."
+ restore_if_unset "MAJOR"
+ restore_if_unset "MINOR"
+ restore_if_unset "BUILD"
+ git svn tag $MAJOR.$MINOR.$BUILD -m "Tagging version $MAJOR.$MINOR.$BUILD" \
+ || die "'git svn tag' failed."
+fi
+
+if [ $STEP -le 19 ] ; then
+ echo ">>> Step 19: Cleanup."
+ restore_if_unset "CURRENT_BRANCH"
+ git checkout -f $CURRENT_BRANCH
+ [[ "$TEMP_BRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TEMP_BRANCH
+ [[ "$BRANCHNAME" != "$CURRENT_BRANCH" ]] && git branch -D $BRANCHNAME
+ [[ "$TRUNKBRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TRUNKBRANCH
+fi
+
+if [ $STEP -le 20 ] ; then
+ echo ">>> Step 20: Done!"
+ restore_if_unset "MAJOR"
+ restore_if_unset "MINOR"
+ restore_if_unset "BUILD"
+ echo "Congratulations, you have successfully created the trunk revision \
+$MAJOR.$MINOR.$BUILD. Please don't forget to update the v8rel spreadsheet, \
+and to roll this new version into Chromium."
+ # Clean up all temporary files.
+ rm -f "$PERSISTFILE_BASENAME"*
+fi
diff --git a/tools/test-wrapper-gypbuild.py b/tools/test-wrapper-gypbuild.py
index 9bc6bf6..ad5449a 100755
--- a/tools/test-wrapper-gypbuild.py
+++ b/tools/test-wrapper-gypbuild.py
@@ -53,6 +53,9 @@
result.add_option("--outdir",
help='Base output directory',
default='out')
+ result.add_option("--no-presubmit",
+ help='Skip presubmit checks',
+ default=False, action="store_true")
# Flags this wrapper script handles itself:
result.add_option("-m", "--mode",
@@ -202,22 +205,31 @@
return 1
workspace = abspath(join(dirname(sys.argv[0]), '..'))
+
+ if not options.no_presubmit:
+ print ">>> running presubmit tests"
+ subprocess.call([workspace + '/tools/presubmit.py'])
+
args_for_children = [workspace + '/tools/test.py'] + PassOnOptions(options)
args_for_children += ['--no-build', '--build-system=gyp']
for arg in args:
args_for_children += [arg]
returncodes = 0
+ env = os.environ
for mode in options.mode:
for arch in options.arch:
print ">>> running tests for %s.%s" % (arch, mode)
- shell = workspace + '/' + options.outdir + '/' + arch + '.' + mode + "/d8"
+ shellpath = workspace + '/' + options.outdir + '/' + arch + '.' + mode
+ env['LD_LIBRARY_PATH'] = shellpath + '/lib.target'
+ shell = shellpath + "/d8"
child = subprocess.Popen(' '.join(args_for_children +
['--arch=' + arch] +
['--mode=' + mode] +
['--shell=' + shell]),
shell=True,
- cwd=workspace)
+ cwd=workspace,
+ env=env)
returncodes += child.wait()
return returncodes
diff --git a/tools/test.py b/tools/test.py
index d40159c..ecc0062 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -1164,6 +1164,7 @@
ARCH_GUESS = utils.GuessArchitecture()
+TIMEOUT_DEFAULT = 60;
def BuildOptions():
@@ -1188,7 +1189,7 @@
result.add_option("-s", "--suite", help="A test suite",
default=[], action="append")
result.add_option("-t", "--timeout", help="Timeout in seconds",
- default=60, type="int")
+ default=-1, type="int")
result.add_option("--arch", help='The architecture to run tests for',
default='none')
result.add_option("--snapshot", help="Run the tests with snapshot turned on",
@@ -1262,6 +1263,12 @@
if options.arch == 'none':
options.arch = ARCH_GUESS
options.scons_flags.append("arch=" + options.arch)
+ # Simulators are slow, therefore allow a longer default timeout.
+ if options.timeout == -1:
+ if options.arch == 'arm' or options.arch == 'mips':
+ options.timeout = 2 * TIMEOUT_DEFAULT;
+ else:
+ options.timeout = TIMEOUT_DEFAULT;
if options.snapshot:
options.scons_flags.append("snapshot=on")
global VARIANT_FLAGS