Browse Source

Upgrade V8 to 3.6.1

Ryan Dahl 13 years ago
parent
commit
0bca54444a
  1. 43
      deps/v8/ChangeLog
  2. 5
      deps/v8/Makefile
  3. 2
      deps/v8/benchmarks/crypto.js
  4. 50
      deps/v8/benchmarks/earley-boyer.js
  5. 6
      deps/v8/benchmarks/regexp.js
  6. 10
      deps/v8/build/all.gyp
  7. 10
      deps/v8/build/common.gypi
  8. 7
      deps/v8/build/standalone.gypi
  9. 4
      deps/v8/include/v8.h
  10. 6
      deps/v8/samples/shell.cc
  11. 2
      deps/v8/src/accessors.cc
  12. 8
      deps/v8/src/arm/assembler-arm.cc
  13. 16
      deps/v8/src/arm/builtins-arm.cc
  14. 225
      deps/v8/src/arm/code-stubs-arm.cc
  15. 619
      deps/v8/src/arm/full-codegen-arm.cc
  16. 6
      deps/v8/src/arm/ic-arm.cc
  17. 15
      deps/v8/src/arm/lithium-codegen-arm.cc
  18. 40
      deps/v8/src/arm/macro-assembler-arm.cc
  19. 10
      deps/v8/src/arm/macro-assembler-arm.h
  20. 2
      deps/v8/src/arm/regexp-macro-assembler-arm.cc
  21. 6
      deps/v8/src/arm/stub-cache-arm.cc
  22. 63
      deps/v8/src/array.js
  23. 34
      deps/v8/src/ast.cc
  24. 134
      deps/v8/src/ast.h
  25. 20
      deps/v8/src/bootstrapper.cc
  26. 6
      deps/v8/src/checks.h
  27. 11
      deps/v8/src/contexts.cc
  28. 31
      deps/v8/src/contexts.h
  29. 4
      deps/v8/src/conversions.h
  30. 14
      deps/v8/src/d8.cc
  31. 2
      deps/v8/src/d8.js
  32. 11
      deps/v8/src/date.js
  33. 1
      deps/v8/src/elements.cc
  34. 6
      deps/v8/src/extensions/externalize-string-extension.cc
  35. 92
      deps/v8/src/full-codegen.cc
  36. 89
      deps/v8/src/full-codegen.h
  37. 84
      deps/v8/src/heap.cc
  38. 25
      deps/v8/src/heap.h
  39. 18
      deps/v8/src/hydrogen-instructions.cc
  40. 27
      deps/v8/src/hydrogen-instructions.h
  41. 450
      deps/v8/src/hydrogen.cc
  42. 12
      deps/v8/src/hydrogen.h
  43. 14
      deps/v8/src/ia32/builtins-ia32.cc
  44. 109
      deps/v8/src/ia32/code-stubs-ia32.cc
  45. 671
      deps/v8/src/ia32/full-codegen-ia32.cc
  46. 4
      deps/v8/src/ia32/ic-ia32.cc
  47. 12
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  48. 50
      deps/v8/src/ia32/macro-assembler-ia32.cc
  49. 21
      deps/v8/src/ia32/macro-assembler-ia32.h
  50. 2
      deps/v8/src/ia32/regexp-macro-assembler-ia32.cc
  51. 2
      deps/v8/src/ia32/stub-cache-ia32.cc
  52. 5
      deps/v8/src/isolate.cc
  53. 4
      deps/v8/src/isolate.h
  54. 5
      deps/v8/src/json.js
  55. 8
      deps/v8/src/jsregexp.cc
  56. 2
      deps/v8/src/jsregexp.h
  57. 7
      deps/v8/src/liveedit.cc
  58. 18
      deps/v8/src/macros.py
  59. 14
      deps/v8/src/math.js
  60. 570
      deps/v8/src/messages.js
  61. 46
      deps/v8/src/mips/assembler-mips.cc
  62. 12
      deps/v8/src/mips/builtins-mips.cc
  63. 238
      deps/v8/src/mips/code-stubs-mips.cc
  64. 6
      deps/v8/src/mips/constants-mips.h
  65. 113
      deps/v8/src/mips/frames-mips.h
  66. 206
      deps/v8/src/mips/full-codegen-mips.cc
  67. 6
      deps/v8/src/mips/ic-mips.cc
  68. 148
      deps/v8/src/mips/macro-assembler-mips.cc
  69. 21
      deps/v8/src/mips/macro-assembler-mips.h
  70. 2
      deps/v8/src/mips/regexp-macro-assembler-mips.cc
  71. 17
      deps/v8/src/mips/simulator-mips.cc
  72. 6
      deps/v8/src/mips/stub-cache-mips.cc
  73. 12
      deps/v8/src/mksnapshot.cc
  74. 16
      deps/v8/src/objects-inl.h
  75. 2
      deps/v8/src/objects.cc
  76. 5
      deps/v8/src/objects.h
  77. 120
      deps/v8/src/parser.cc
  78. 11
      deps/v8/src/parser.h
  79. 6
      deps/v8/src/platform-linux.cc
  80. 98
      deps/v8/src/prettyprinter.cc
  81. 3
      deps/v8/src/prettyprinter.h
  82. 34
      deps/v8/src/profile-generator.cc
  83. 6
      deps/v8/src/profile-generator.h
  84. 6
      deps/v8/src/regexp.js
  85. 6
      deps/v8/src/runtime-profiler.cc
  86. 125
      deps/v8/src/runtime.cc
  87. 13
      deps/v8/src/runtime.h
  88. 1
      deps/v8/src/runtime.js
  89. 2
      deps/v8/src/scanner-base.h
  90. 2
      deps/v8/src/scanner.h
  91. 65
      deps/v8/src/scopeinfo.cc
  92. 151
      deps/v8/src/scopes.cc
  93. 19
      deps/v8/src/scopes.h
  94. 3
      deps/v8/src/spaces-inl.h
  95. 60
      deps/v8/src/string.js
  96. 2
      deps/v8/src/stub-cache.h
  97. 1
      deps/v8/src/token.h
  98. 7
      deps/v8/src/uri.js
  99. 261
      deps/v8/src/v8natives.js
  100. 31
      deps/v8/src/variables.cc

43
deps/v8/ChangeLog

@ -1,3 +1,46 @@
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
the GYP-build.
Various bugfixes.
2011-08-29: Version 3.5.9 2011-08-29: Version 3.5.9
Made FromPropertyDescriptor not trigger inherited setters. Made FromPropertyDescriptor not trigger inherited setters.

5
deps/v8/Makefile

@ -98,8 +98,9 @@ CHECKS = $(addsuffix .check,$(BUILDS))
# File where previously used GYPFLAGS are stored. # File where previously used GYPFLAGS are stored.
ENVFILE = $(OUTDIR)/environment ENVFILE = $(OUTDIR)/environment
.PHONY: all clean $(ENVFILE).new \ .PHONY: all check clean $(ENVFILE).new \
$(ARCHES) $(MODES) $(BUILDS) $(addsuffix .clean,$(ARCHES)) $(ARCHES) $(MODES) $(BUILDS) $(CHECKS) $(addsuffix .clean,$(ARCHES)) \
$(addsuffix .check,$(MODES)) $(addsuffix .check,$(ARCHES))
# Target definitions. "all" is the default. # Target definitions. "all" is the default.
all: $(MODES) all: $(MODES)

2
deps/v8/benchmarks/crypto.js

@ -1406,7 +1406,7 @@ function rng_seed_int(x) {
// Mix in the current time (w/milliseconds) into the pool // Mix in the current time (w/milliseconds) into the pool
function rng_seed_time() { 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. // results dependent on the current date.
rng_seed_int(1122926989487); rng_seed_int(1122926989487);
} }

50
deps/v8/benchmarks/earley-boyer.js

@ -134,7 +134,7 @@ function sc_rempropBang(sym, key) {
/*** META ((export #t)) */ /*** META ((export #t)) */
function sc_any2String(o) { function sc_any2String(o) {
return jsstring2string(sc_toDisplayString(o)); return jsstring2string(sc_toDisplayString(o));
} }
/*** META ((export #t) /*** META ((export #t)
(peephole (infix 2 2 "===")) (peephole (infix 2 2 "==="))
@ -923,7 +923,7 @@ function sc_dualAppendBang(l1, l2) {
tmp.cdr = l2; tmp.cdr = l2;
return l1; return l1;
} }
/*** META ((export #t)) */ /*** META ((export #t)) */
function sc_appendBang() { function sc_appendBang() {
var res = null; var res = null;
@ -1163,7 +1163,7 @@ sc_Char.readable2char = {
"us": "\037", "us": "\037",
"sp": "\040", "sp": "\040",
"del": "\177"}; "del": "\177"};
sc_Char.prototype.toString = function() { sc_Char.prototype.toString = function() {
return this.val; return this.val;
}; };
@ -1533,7 +1533,7 @@ function sc_mapBang(proc, l1) {
} }
return l1_orig; return l1_orig;
} }
/*** META ((export #t)) */ /*** META ((export #t)) */
function sc_forEach(proc, l1) { function sc_forEach(proc, l1) {
if (l1 === undefined) if (l1 === undefined)
@ -1871,7 +1871,7 @@ function sc_jsNew(c) {
evalStr += ", arguments[" + i + "]"; evalStr += ", arguments[" + i + "]";
evalStr +=")"; evalStr +=")";
return eval(evalStr); return eval(evalStr);
} }
// ======================== RegExp ==================== // ======================== RegExp ====================
/*** META ((export #t)) */ /*** META ((export #t)) */
@ -1883,9 +1883,9 @@ function sc_pregexp(re) {
function sc_pregexpMatch(re, s) { function sc_pregexpMatch(re, s) {
var reg = (re instanceof RegExp) ? re : sc_pregexp(re); var reg = (re instanceof RegExp) ? re : sc_pregexp(re);
var tmp = reg.exec(sc_string2jsstring(s)); var tmp = reg.exec(sc_string2jsstring(s));
if (tmp == null) return false; if (tmp == null) return false;
var res = null; var res = null;
for (var i = tmp.length-1; i >= 0; i--) { for (var i = tmp.length-1; i >= 0; i--) {
if (tmp[i] !== null) { if (tmp[i] !== null) {
@ -1896,7 +1896,7 @@ function sc_pregexpMatch(re, s) {
} }
return res; return res;
} }
/*** META ((export #t)) */ /*** META ((export #t)) */
function sc_pregexpReplace(re, s1, s2) { function sc_pregexpReplace(re, s1, s2) {
var reg; var reg;
@ -1914,7 +1914,7 @@ function sc_pregexpReplace(re, s1, s2) {
return jss1.replace(reg, jss2); return jss1.replace(reg, jss2);
} }
/*** META ((export pregexp-replace*)) */ /*** META ((export pregexp-replace*)) */
function sc_pregexpReplaceAll(re, s1, s2) { function sc_pregexpReplaceAll(re, s1, s2) {
var reg; var reg;
@ -1945,7 +1945,7 @@ function sc_pregexpSplit(re, s) {
return sc_vector2list(tmp); return sc_vector2list(tmp);
} }
/* =========================================================================== */ /* =========================================================================== */
/* Other library stuff */ /* Other library stuff */
@ -2136,7 +2136,7 @@ sc_ErrorInputPort.prototype.getNextChar = function() {
sc_ErrorInputPort.prototype.isCharReady = function() { sc_ErrorInputPort.prototype.isCharReady = function() {
return false; return false;
}; };
/* .............. String port ..........................*/ /* .............. String port ..........................*/
@ -2200,7 +2200,7 @@ sc_Tokenizer.prototype.readToken = function() {
}; };
sc_Tokenizer.prototype.nextToken = function() { sc_Tokenizer.prototype.nextToken = function() {
var port = this.port; var port = this.port;
function isNumberChar(c) { function isNumberChar(c) {
return (c >= "0" && c <= "9"); return (c >= "0" && c <= "9");
}; };
@ -2280,7 +2280,7 @@ sc_Tokenizer.prototype.nextToken = function() {
else else
return new sc_Token(12/*NUMBER*/, res - 0); return new sc_Token(12/*NUMBER*/, res - 0);
}; };
function skipWhitespaceAndComments() { function skipWhitespaceAndComments() {
var done = false; var done = false;
while (!done) { while (!done) {
@ -2299,7 +2299,7 @@ sc_Tokenizer.prototype.nextToken = function() {
} }
} }
}; };
function readDot() { function readDot() {
if (isWhitespace(port.peekChar())) if (isWhitespace(port.peekChar()))
return new sc_Token(10/*DOT*/); return new sc_Token(10/*DOT*/);
@ -2429,7 +2429,7 @@ sc_Reader.prototype.read = function() {
while (true) { while (true) {
var token = tokenizer.peekToken(); var token = tokenizer.peekToken();
switch (token.type) { switch (token.type) {
case 2/*CLOSE_PAR*/: case 2/*CLOSE_PAR*/:
case 4/*CLOSE_BRACE*/: case 4/*CLOSE_BRACE*/:
@ -2491,7 +2491,7 @@ sc_Reader.prototype.read = function() {
else else
throw "bad reference: " + nb; throw "bad reference: " + nb;
}; };
var tokenizer = this.tokenizer; var tokenizer = this.tokenizer;
var token = tokenizer.readToken(); var token = tokenizer.readToken();
@ -2499,7 +2499,7 @@ sc_Reader.prototype.read = function() {
// handle error // handle error
if (token.type === 13/*ERROR*/) if (token.type === 13/*ERROR*/)
throw token.val; throw token.val;
switch (token.type) { switch (token.type) {
case 1/*OPEN_PAR*/: case 1/*OPEN_PAR*/:
case 3/*OPEN_BRACE*/: case 3/*OPEN_BRACE*/:
@ -2550,7 +2550,7 @@ function sc_peekChar(port) {
port = SC_DEFAULT_IN; // THREAD: shared var... port = SC_DEFAULT_IN; // THREAD: shared var...
var t = port.peekChar(); var t = port.peekChar();
return t === SC_EOF_OBJECT? t: new sc_Char(t); return t === SC_EOF_OBJECT? t: new sc_Char(t);
} }
/*** META ((export #t) /*** META ((export #t)
(type bool)) (type bool))
*/ */
@ -2722,7 +2722,7 @@ sc_StringOutputPort.prototype.close = function() {
function sc_getOutputString(sp) { function sc_getOutputString(sp) {
return sc_jsstring2string(sp.res); return sc_jsstring2string(sp.res);
} }
function sc_ErrorOutputPort() { function sc_ErrorOutputPort() {
} }
@ -2852,7 +2852,7 @@ function sc_newline(p) {
p = SC_DEFAULT_OUT; p = SC_DEFAULT_OUT;
p.appendJSString("\n"); p.appendJSString("\n");
} }
/* ------------------ write-char ---------------------------------------------------*/ /* ------------------ write-char ---------------------------------------------------*/
/*** META ((export #t)) */ /*** META ((export #t)) */
@ -2927,7 +2927,7 @@ sc_Pair.prototype.sc_toWriteCircleString = function(symb, inList) {
} }
var res = ""; var res = "";
if (this[symb] !== undefined) { // implies > 0 if (this[symb] !== undefined) { // implies > 0
this[symb + "use"] = true; this[symb + "use"] = true;
if (inList) if (inList)
@ -2939,10 +2939,10 @@ sc_Pair.prototype.sc_toWriteCircleString = function(symb, inList) {
if (!inList) if (!inList)
res += "("; res += "(";
// print car // print car
res += sc_genToWriteCircleString(this.car, symb); res += sc_genToWriteCircleString(this.car, symb);
if (sc_isPair(this.cdr)) { if (sc_isPair(this.cdr)) {
res += " " + this.cdr.sc_toWriteCircleString(symb, true); res += " " + this.cdr.sc_toWriteCircleString(symb, true);
} else if (this.cdr !== null) { } else if (this.cdr !== null) {
@ -3072,7 +3072,7 @@ function sc_format(s, args) {
p.appendJSString(arguments[j].toString(2)); p.appendJSString(arguments[j].toString(2));
i += 2; j++; i += 2; j++;
break; break;
case 37: case 37:
case 110: case 110:
// %, n // %, n
@ -3186,7 +3186,7 @@ function sc_isEqual(o1, o2) {
function sc_number2symbol(x, radix) { function sc_number2symbol(x, radix) {
return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix); return sc_SYMBOL_PREFIX + sc_number2jsstring(x, radix);
} }
/*** META ((export number->string integer->string)) */ /*** META ((export number->string integer->string)) */
var sc_number2string = sc_number2jsstring; var sc_number2string = sc_number2jsstring;

6
deps/v8/benchmarks/regexp.js

@ -33,7 +33,7 @@
// the popularity of the pages where it occurs and the number of times // the popularity of the pages where it occurs and the number of times
// it is executed while loading each page. Furthermore the literal // it is executed while loading each page. Furthermore the literal
// letters in the data are encoded using ROT13 in a way that does not // 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. // scrambled to exercise the regexp engine on different input strings.
@ -47,7 +47,7 @@ function RegExpSetup() {
regExpBenchmark = new RegExpBenchmark(); regExpBenchmark = new RegExpBenchmark();
RegExpRun(); // run once to get system initialized RegExpRun(); // run once to get system initialized
} }
function RegExpRun() { function RegExpRun() {
regExpBenchmark.run(); regExpBenchmark.run();
} }
@ -1759,6 +1759,6 @@ function RegExpBenchmark() {
runBlock11(); runBlock11();
} }
} }
this.run = run; this.run = run;
} }

10
deps/v8/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 # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
@ -11,13 +11,7 @@
'../preparser/preparser.gyp:*', '../preparser/preparser.gyp:*',
'../samples/samples.gyp:*', '../samples/samples.gyp:*',
'../src/d8.gyp:d8', '../src/d8.gyp:d8',
], '../test/cctest/cctest.gyp:*',
'conditions': [
[ 'component!="shared_library"', {
'dependencies': [
'../test/cctest/cctest.gyp:*',
],
}]
], ],
} }
] ]

10
deps/v8/build/common.gypi

@ -173,6 +173,14 @@
}, },
}, },
}], }],
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
'conditions': [
[ 'target_arch=="ia32"', {
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
],
}],
], ],
'configurations': { 'configurations': {
'Debug': { 'Debug': {
@ -207,7 +215,7 @@
'cflags': [ '-I/usr/local/include' ], 'cflags': [ '-I/usr/local/include' ],
}], }],
['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
'cflags': [ '-Wall', '-W', '-Wno-unused-parameter', 'cflags': [ '-Wall', '-Werror', '-W', '-Wno-unused-parameter',
'-Wnon-virtual-dtor' ], '-Wnon-virtual-dtor' ],
}], }],
], ],

7
deps/v8/build/standalone.gypi

@ -74,15 +74,11 @@
'conditions': [ 'conditions': [
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
'target_defaults': { 'target_defaults': {
'cflags': [ '-Wall', '-W', '-Wno-unused-parameter', 'cflags': [ '-Wall', '-Werror', '-W', '-Wno-unused-parameter',
'-Wnon-virtual-dtor', '-pthread', '-fno-rtti', '-Wnon-virtual-dtor', '-pthread', '-fno-rtti',
'-fno-exceptions', '-pedantic' ], '-fno-exceptions', '-pedantic' ],
'ldflags': [ '-pthread', ], 'ldflags': [ '-pthread', ],
'conditions': [ 'conditions': [
[ 'target_arch=="ia32"', {
'cflags': [ '-m32' ],
'ldflags': [ '-m32' ],
}],
[ 'OS=="linux"', { [ 'OS=="linux"', {
'cflags': [ '-ansi' ], 'cflags': [ '-ansi' ],
}], }],
@ -172,6 +168,7 @@
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics
'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror
'GCC_VERSION': '4.2', 'GCC_VERSION': '4.2',
'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof
'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4 'MACOSX_DEPLOYMENT_TARGET': '10.4', # -mmacosx-version-min=10.4

4
deps/v8/include/v8.h

@ -1656,7 +1656,7 @@ class Object : public Value {
V8EXPORT bool IsCallable(); 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. * ObjectTemplate::SetCallAsFunctionHandler method.
*/ */
V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv, V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv,
@ -3562,7 +3562,7 @@ class V8EXPORT Context {
* // V8 Now no longer locked. * // V8 Now no longer locked.
* \endcode * \endcode
* *
* *
*/ */
class V8EXPORT Unlocker { class V8EXPORT Unlocker {
public: public:

6
deps/v8/samples/shell.cc

@ -250,16 +250,14 @@ void RunShell(v8::Handle<v8::Context> context) {
static const int kBufferSize = 256; static const int kBufferSize = 256;
// Enter the execution environment before evaluating any code. // Enter the execution environment before evaluating any code.
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
v8::Local<v8::String> name(v8::String::New("(shell)"));
while (true) { while (true) {
char buffer[kBufferSize]; char buffer[kBufferSize];
printf("> "); printf("> ");
char* str = fgets(buffer, kBufferSize, stdin); char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break; if (str == NULL) break;
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
ExecuteString(v8::String::New(str), ExecuteString(v8::String::New(str), name, true, true);
v8::String::New("(shell)"),
true,
true);
} }
printf("\n"); printf("\n");
} }

2
deps/v8/src/accessors.cc

@ -599,6 +599,7 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
if (!found_it) return isolate->heap()->undefined_value(); if (!found_it) return isolate->heap()->undefined_value();
Handle<JSFunction> function(holder, isolate); Handle<JSFunction> function(holder, isolate);
if (function->shared()->native()) return isolate->heap()->null_value();
// Find the top invocation of the function by traversing frames. // Find the top invocation of the function by traversing frames.
List<JSFunction*> functions(2); List<JSFunction*> functions(2);
for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
@ -732,6 +733,7 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
bool found_it = false; bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it); JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return isolate->heap()->undefined_value(); if (!found_it) return isolate->heap()->undefined_value();
if (holder->shared()->native()) return isolate->heap()->null_value();
Handle<JSFunction> function(holder, isolate); Handle<JSFunction> function(holder, isolate);
FrameFunctionIterator it(isolate, no_alloc); FrameFunctionIterator it(isolate, no_alloc);

8
deps/v8/src/arm/assembler-arm.cc

@ -692,11 +692,11 @@ void Assembler::bind(Label* L) {
void Assembler::next(Label* L) { void Assembler::next(Label* L) {
ASSERT(L->is_linked()); ASSERT(L->is_linked());
int link = target_at(L->pos()); int link = target_at(L->pos());
if (link > 0) { if (link == kEndOfChain) {
L->link_to(link);
} else {
ASSERT(link == kEndOfChain);
L->Unuse(); L->Unuse();
} else {
ASSERT(link >= 0);
L->link_to(link);
} }
} }

16
deps/v8/src/arm/builtins-arm.cc

@ -138,7 +138,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
__ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset)); __ str(scratch1, FieldMemOperand(result, JSArray::kElementsOffset));
// Clear the heap tag on the elements array. // Clear the heap tag on the elements array.
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ sub(scratch1, scratch1, Operand(kHeapObjectTag)); __ sub(scratch1, scratch1, Operand(kHeapObjectTag));
// Initialize the FixedArray and fill it with holes. FixedArray length is // Initialize the FixedArray and fill it with holes. FixedArray length is
@ -207,7 +207,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// Allocate the JSArray object together with space for a FixedArray with the // Allocate the JSArray object together with space for a FixedArray with the
// requested number of elements. // requested number of elements.
__ bind(&not_empty); __ bind(&not_empty);
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ mov(elements_array_end, __ mov(elements_array_end,
Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize)); Operand((JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize));
__ add(elements_array_end, __ add(elements_array_end,
@ -243,7 +243,7 @@ static void AllocateJSArray(MacroAssembler* masm,
FieldMemOperand(result, JSArray::kElementsOffset)); FieldMemOperand(result, JSArray::kElementsOffset));
// Clear the heap tag on the elements array. // Clear the heap tag on the elements array.
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ sub(elements_array_storage, __ sub(elements_array_storage,
elements_array_storage, elements_array_storage,
Operand(kHeapObjectTag)); Operand(kHeapObjectTag));
@ -255,7 +255,7 @@ static void AllocateJSArray(MacroAssembler* masm,
__ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex); __ LoadRoot(scratch1, Heap::kFixedArrayMapRootIndex);
ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset); ASSERT_EQ(0 * kPointerSize, FixedArray::kMapOffset);
__ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex)); __ str(scratch1, MemOperand(elements_array_storage, kPointerSize, PostIndex));
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ tst(array_size, array_size); __ tst(array_size, array_size);
// Length of the FixedArray is the number of pre-allocated elements if // 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 // the actual JSArray has length 0 and the size of the JSArray for non-empty
@ -272,7 +272,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// result: JSObject // result: JSObject
// elements_array_storage: elements array element storage // elements_array_storage: elements array element storage
// array_size: smi-tagged size of elements array // array_size: smi-tagged size of elements array
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ add(elements_array_end, __ add(elements_array_end,
elements_array_storage, elements_array_storage,
Operand(array_size, LSL, kPointerSizeLog2 - kSmiTagSize)); Operand(array_size, LSL, kPointerSizeLog2 - kSmiTagSize));
@ -337,14 +337,14 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ bind(&argc_one_or_more); __ bind(&argc_one_or_more);
__ cmp(r0, Operand(1)); __ cmp(r0, Operand(1));
__ b(ne, &argc_two_or_more); __ b(ne, &argc_two_or_more);
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ ldr(r2, MemOperand(sp)); // Get the argument from the stack. __ ldr(r2, MemOperand(sp)); // Get the argument from the stack.
__ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC); __ and_(r3, r2, Operand(kIntptrSignBit | kSmiTagMask), SetCC);
__ b(ne, call_generic_code); __ b(ne, call_generic_code);
// Handle construction of an empty array of a certain size. Bail out if size // Handle construction of an empty array of a certain size. Bail out if size
// is too large to actually allocate an elements array. // is too large to actually allocate an elements array.
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); __ cmp(r2, Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
__ b(ge, call_generic_code); __ b(ge, call_generic_code);
@ -571,7 +571,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// Is it a String? // Is it a String?
__ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset)); __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0); STATIC_ASSERT(kNotStringTag != 0);
__ tst(r3, Operand(kIsNotStringMask)); __ tst(r3, Operand(kIsNotStringMask));
__ b(ne, &convert_argument); __ b(ne, &convert_argument);
__ mov(argument, r0); __ mov(argument, r0);

225
deps/v8/src/arm/code-stubs-arm.cc

@ -4389,8 +4389,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// a sequential string or an external string. // a sequential string or an external string.
// In the case of a sliced string its offset has to be taken into account. // In the case of a sliced string its offset has to be taken into account.
Label cons_string, check_encoding; Label cons_string, check_encoding;
STATIC_ASSERT((kConsStringTag < kExternalStringTag)); STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
__ cmp(r1, Operand(kExternalStringTag)); __ cmp(r1, Operand(kExternalStringTag));
__ b(lt, &cons_string); __ b(lt, &cons_string);
__ b(eq, &runtime); __ b(eq, &runtime);
@ -4487,7 +4487,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// frame. Therefore we have to use fp, which points exactly to two pointer // 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 // 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.) // 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. // If slice offset is not 0, load the length from the original sliced string.
// Argument 4, r3: End of string data // Argument 4, r3: End of string data
// Argument 3, r2: Start of string data // Argument 3, r2: Start of string data
@ -4495,7 +4495,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ add(r9, r8, Operand(r9, LSL, r3)); __ add(r9, r8, Operand(r9, LSL, r3));
__ add(r2, r9, Operand(r1, 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)); __ mov(r8, Operand(r8, ASR, kSmiTagSize));
__ add(r3, r9, Operand(r8, LSL, r3)); __ add(r3, r9, Operand(r8, LSL, r3));
@ -4503,7 +4503,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Already there // Already there
// Argument 1 (r0): Subject string. // Argument 1 (r0): Subject string.
// Already there __ mov(r0, subject);
// Locate the code entry and call it. // Locate the code entry and call it.
__ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); __ add(r7, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
@ -4520,12 +4520,12 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Check the result. // Check the result.
Label success; Label success;
__ cmp(subject, Operand(NativeRegExpMacroAssembler::SUCCESS)); __ cmp(r0, Operand(NativeRegExpMacroAssembler::SUCCESS));
__ b(eq, &success); __ b(eq, &success);
Label failure; Label failure;
__ cmp(subject, Operand(NativeRegExpMacroAssembler::FAILURE)); __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE));
__ b(eq, &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. // If not exception it can only be retry. Handle that in the runtime system.
__ b(ne, &runtime); __ b(ne, &runtime);
// Result must now be exception. If there is no pending exception already a // Result must now be exception. If there is no pending exception already a
@ -4537,18 +4537,18 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address, __ mov(r2, Operand(ExternalReference(Isolate::k_pending_exception_address,
isolate))); isolate)));
__ ldr(r0, MemOperand(r2, 0)); __ ldr(r0, MemOperand(r2, 0));
__ cmp(subject, r1); __ cmp(r0, r1);
__ b(eq, &runtime); __ b(eq, &runtime);
__ str(r1, MemOperand(r2, 0)); // Clear pending exception. __ str(r1, MemOperand(r2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable. // Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(ip, Heap::kTerminationExceptionRootIndex); __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex);
__ cmp(subject, ip);
Label termination_exception; Label termination_exception;
__ b(eq, &termination_exception); __ b(eq, &termination_exception);
__ Throw(subject); // Expects thrown value in r0. __ Throw(r0); // Expects thrown value in r0.
__ bind(&termination_exception); __ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0. __ ThrowUncatchable(TERMINATION, r0); // Expects thrown value in r0.
@ -4857,8 +4857,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Handle non-flat strings. // Handle non-flat strings.
__ and_(result_, result_, Operand(kStringRepresentationMask)); __ and_(result_, result_, Operand(kStringRepresentationMask));
STATIC_ASSERT((kConsStringTag < kExternalStringTag)); STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
__ cmp(result_, Operand(kExternalStringTag)); __ cmp(result_, Operand(kExternalStringTag));
__ b(gt, &sliced_string); __ b(gt, &sliced_string);
__ b(eq, &call_runtime_); __ b(eq, &call_runtime_);
@ -4894,7 +4894,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Check for 1-byte or 2-byte string. // Check for 1-byte or 2-byte string.
__ bind(&flat_string); __ bind(&flat_string);
STATIC_ASSERT(kAsciiStringTag != 0); STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ tst(result_, Operand(kStringEncodingMask)); __ tst(result_, Operand(kStringEncodingMask));
__ b(ne, &ascii_string); __ b(ne, &ascii_string);
@ -5468,11 +5469,6 @@ void SubStringStub::Generate(MacroAssembler* masm) {
Register to = r6; Register to = r6;
Register from = r7; 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)); __ Ldrd(to, from, MemOperand(sp, kToOffset));
STATIC_ASSERT(kFromOffset == kToOffset + 4); STATIC_ASSERT(kFromOffset == kToOffset + 4);
STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
@ -5490,64 +5486,79 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ b(mi, &runtime); // Fail if from > to. __ b(mi, &runtime); // Fail if from > to.
// Special handling of sub-strings of length 1 and 2. One character strings // 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 // 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)); __ cmp(r2, Operand(2));
__ b(lt, &runtime); __ b(lt, &runtime);
// r2: length // r2: result string length
// r3: from index (untaged smi) // r3: from index (untagged smi)
// r6 (a.k.a. to): to (smi) // r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi) // r7 (a.k.a. from): from offset (smi)
// Make sure first argument is a sequential (or flat) string. // Make sure first argument is a sequential (or flat) string.
__ ldr(r5, MemOperand(sp, kStringOffset)); __ ldr(r0, MemOperand(sp, kStringOffset));
STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ JumpIfSmi(r5, &runtime); __ JumpIfSmi(r0, &runtime);
Condition is_string = masm->IsObjectStringType(r5, r1); Condition is_string = masm->IsObjectStringType(r0, r1);
__ b(NegateCondition(is_string), &runtime); __ 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 // r1: instance type
// r2: length // r2: result string length
// r3: from index (untagged smi) // r3: from index (untagged smi)
// r5: string
// r6 (a.k.a. to): to (smi) // r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (smi) // r7 (a.k.a. from): from offset (smi)
Label seq_string; Label seq_string;
__ and_(r4, r1, Operand(kStringRepresentationMask)); __ and_(r4, r1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag < kConsStringTag); STATIC_ASSERT(kSeqStringTag < kConsStringTag);
STATIC_ASSERT(kConsStringTag < kExternalStringTag); STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT(kConsStringTag < kSlicedStringTag);
__ cmp(r4, Operand(kConsStringTag)); __ 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. __ b(lt, &seq_string); // Sequential strings are handled directly.
// Cons string. Try to recurse (once) on the first substring. // Cons string. Try to recurse (once) on the first substring.
// (This adds a little more generality than necessary to handle flattened // (This adds a little more generality than necessary to handle flattened
// cons strings, but not much). // cons strings, but not much).
__ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); __ ldr(r0, FieldMemOperand(r0, ConsString::kFirstOffset));
__ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset));
__ tst(r1, Operand(kStringRepresentationMask)); __ tst(r1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag == 0); 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. // Definitly a sequential string.
__ bind(&seq_string); __ bind(&seq_string);
// r1: instance type. // r0: original string
// r2: length // r1: instance type
// r3: from index (untaged smi) // r2: result string length
// r5: string // r3: from index (untagged smi)
// r6 (a.k.a. to): to (smi) // r6 (a.k.a. to): to (smi)
// r7 (a.k.a. from): from offset (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)); __ cmp(r4, Operand(to));
__ b(lt, &runtime); // Fail if to > length. __ b(lt, &runtime); // Fail if to > length.
to = no_reg; to = no_reg;
// r1: instance type. // r0: original string or left hand side of the original cons string.
// r2: result string length. // r1: instance type
// r3: from index (untaged smi) // r2: result string length
// r5: string. // r3: from index (untagged smi)
// r7 (a.k.a. from): from offset (smi) // r7 (a.k.a. from): from offset (smi)
// Check for flat ASCII string. // Check for flat ASCII string.
Label non_ascii_flat; Label non_ascii_flat;
@ -5561,82 +5572,146 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Sub string of length 2 requested. // Sub string of length 2 requested.
// Get the two characters forming the sub string. // Get the two characters forming the sub string.
__ add(r5, r5, Operand(r3)); __ add(r0, r0, Operand(r3));
__ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); __ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
__ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1)); __ ldrb(r4, FieldMemOperand(r0, SeqAsciiString::kHeaderSize + 1));
// Try to lookup two character string in symbol table. // Try to lookup two character string in symbol table.
Label make_two_character_string; Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe( StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string); masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
Counters* counters = masm->isolate()->counters(); Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->sub_string_native(), 1, r3, r4); __ jmp(&return_r0);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
// r2: result string length. // r2: result string length.
// r3: two characters combined into halfword in little endian byte order. // r3: two characters combined into halfword in little endian byte order.
__ bind(&make_two_character_string); __ bind(&make_two_character_string);
__ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime);
__ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
__ IncrementCounter(counters->sub_string_native(), 1, r3, r4); __ jmp(&return_r0);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
__ bind(&result_longer_than_two); __ 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. // Allocate the result.
__ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime);
// r0: result string. // r0: result string
// r2: result string length. // r2: result string length
// r5: string. // r5: first character of substring to copy
// r7 (a.k.a. from): from offset (smi) // r7 (a.k.a. from): from offset (smi)
// Locate first character of result. // Locate first character of result.
__ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); __ 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. // r0: result string
// r1: first character of result string. // r1: first character of result string
// r2: result string length. // r2: result string length
// r5: first character of sub string to copy. // r5: first character of substring to copy
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
COPY_ASCII | DEST_ALWAYS_ALIGNED); COPY_ASCII | DEST_ALWAYS_ALIGNED);
__ IncrementCounter(counters->sub_string_native(), 1, r3, r4); __ jmp(&return_r0);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
__ bind(&non_ascii_flat); __ bind(&non_ascii_flat);
// r2: result string length. // r0: original string
// r5: string. // r2: result string length
// r7 (a.k.a. from): from offset (smi) // r7 (a.k.a. from): from offset (smi)
// Check for flat two byte string. // 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. // Allocate the result.
__ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime);
// r0: result string. // r0: result string
// r2: result string length. // r2: result string length
// r5: string. // r5: first character of substring to copy
// Locate first character of result. // Locate first character of result.
__ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); __ 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; from = no_reg;
// r0: result string. // r0: result string.
// r1: first character of result. // r1: first character of result.
// r2: result length. // r2: result length.
// r5: first character of string to copy. // r5: first character of substring to copy.
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong( StringHelper::GenerateCopyCharactersLong(
masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED); 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); __ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
__ add(sp, sp, Operand(3 * kPointerSize)); __ add(sp, sp, Operand(3 * kPointerSize));
__ Ret(); __ Ret();

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

@ -193,14 +193,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy any necessary parameters into the context. // Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters(); int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Variable* var = scope()->parameter(i);
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize; (num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack. // Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset)); __ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context. // Store it in the context.
__ mov(r1, Operand(Context::SlotOffset(slot->index()))); __ mov(r1, Operand(Context::SlotOffset(var->index())));
__ str(r0, MemOperand(cp, r1)); __ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved // Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid // registers, so we have to use two more registers to avoid
@ -244,7 +244,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
ArgumentsAccessStub stub(type); ArgumentsAccessStub stub(type);
__ CallStub(&stub); __ CallStub(&stub);
Move(arguments->AsSlot(), r0, r1, r2); SetVar(arguments, r0, r1, r2);
} }
if (FLAG_trace) { if (FLAG_trace) {
@ -258,17 +258,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
scope()->VisitIllegalRedeclaration(this); scope()->VisitIllegalRedeclaration(this);
} else { } else {
PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a // For named function expressions, declare the function name as a
// constant. // constant.
if (scope()->is_function_scope() && scope()->function() != NULL) { 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()); VisitDeclarations(scope()->declarations());
} }
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok; Label ok;
__ LoadRoot(ip, Heap::kStackLimitRootIndex); __ LoadRoot(ip, Heap::kStackLimitRootIndex);
__ cmp(sp, Operand(ip)); __ cmp(sp, Operand(ip));
@ -367,24 +369,28 @@ void FullCodeGenerator::EmitReturnSequence() {
} }
void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
ASSERT(var->IsStackAllocated() || var->IsContextSlot());
} }
void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
codegen()->Move(result_register(), slot); ASSERT(var->IsStackAllocated() || var->IsContextSlot());
codegen()->GetVar(result_register(), var);
} }
void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
codegen()->Move(result_register(), slot); ASSERT(var->IsStackAllocated() || var->IsContextSlot());
codegen()->GetVar(result_register(), var);
__ push(result_register()); __ 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. // 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()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this); codegen()->DoTest(this);
} }
@ -616,45 +622,54 @@ void FullCodeGenerator::Split(Condition cond,
} }
MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { MemOperand FullCodeGenerator::StackOperand(Variable* var) {
switch (slot->type()) { ASSERT(var->IsStackAllocated());
case Slot::PARAMETER: // Offset is negative because higher indexes are at lower addresses.
case Slot::LOCAL: int offset = -var->index() * kPointerSize;
return MemOperand(fp, SlotOffset(slot)); // Adjust by a (parameter or local) base offset.
case Slot::CONTEXT: { if (var->IsParameter()) {
int context_chain_length = offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
scope()->ContextChainLength(slot->var()->scope()); } else {
__ LoadContext(scratch, context_chain_length); offset += JavaScriptFrameConstants::kLocal0Offset;
return ContextOperand(scratch, slot->index()); }
} return MemOperand(fp, offset);
case Slot::LOOKUP: }
UNREACHABLE();
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);
} }
UNREACHABLE();
return MemOperand(r0, 0);
} }
void FullCodeGenerator::Move(Register destination, Slot* source) { void FullCodeGenerator::GetVar(Register dest, Variable* var) {
// Use destination as scratch. // Use destination as scratch.
MemOperand slot_operand = EmitSlotSearch(source, destination); MemOperand location = VarOperand(var, dest);
__ ldr(destination, slot_operand); __ ldr(dest, location);
} }
void FullCodeGenerator::Move(Slot* dst, void FullCodeGenerator::SetVar(Variable* var,
Register src, Register src,
Register scratch1, Register scratch0,
Register scratch2) { Register scratch1) {
ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. ASSERT(var->IsContextSlot() || var->IsStackAllocated());
ASSERT(!scratch1.is(src) && !scratch2.is(src)); ASSERT(!scratch0.is(src));
MemOperand location = EmitSlotSearch(dst, scratch1); ASSERT(!scratch0.is(scratch1));
ASSERT(!scratch1.is(src));
MemOperand location = VarOperand(var, scratch0);
__ str(src, location); __ str(src, location);
// Emit the write barrier code if the location is in the heap. // Emit the write barrier code if the location is in the heap.
if (dst->type() == Slot::CONTEXT) { if (var->IsContextSlot()) {
__ RecordWrite(scratch1, __ RecordWrite(scratch0,
Operand(Context::SlotOffset(dst->index())), Operand(Context::SlotOffset(var->index())),
scratch2, scratch1,
src); src);
} }
} }
@ -687,29 +702,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
} }
void FullCodeGenerator::EmitDeclaration(Variable* variable, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function) { FunctionLiteral* function,
Comment cmnt(masm_, "[ Declaration"); int* global_count) {
ASSERT(variable != NULL); // Must have been resolved. // If it was not possible to allocate the variable at compile time, we
Slot* slot = variable->AsSlot(); // need to "declare" it at runtime to make sure it actually exists in the
ASSERT(slot != NULL); // local context.
switch (slot->type()) { Variable* variable = proxy->var();
case Slot::PARAMETER: switch (variable->location()) {
case Slot::LOCAL: case Variable::UNALLOCATED:
if (mode == Variable::CONST) { ++(*global_count);
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); break;
__ str(ip, MemOperand(fp, SlotOffset(slot)));
} else if (function != NULL) { case Variable::PARAMETER:
case Variable::LOCAL:
if (function != NULL) {
Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function); 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, StackOperand(variable));
} }
break; break;
case Slot::CONTEXT: case Variable::CONTEXT:
// We bypass the general EmitSlotSearch because we know more about
// this specific context.
// The variable in the decl always resides in the current function // The variable in the decl always resides in the current function
// context. // context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@ -721,23 +740,28 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ CompareRoot(r1, Heap::kCatchContextMapRootIndex); __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
__ Check(ne, "Declaration in catch context."); __ Check(ne, "Declaration in catch context.");
} }
if (mode == Variable::CONST) { if (function != NULL) {
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); Comment cmnt(masm_, "[ Declaration");
__ str(ip, ContextOperand(cp, slot->index()));
// No write barrier since the_hole_value is in old space.
} else if (function != NULL) {
VisitForAccumulatorValue(function); VisitForAccumulatorValue(function);
__ str(result_register(), ContextOperand(cp, slot->index())); __ str(result_register(), ContextOperand(cp, variable->index()));
int offset = Context::SlotOffset(slot->index()); int offset = Context::SlotOffset(variable->index());
// We know that we have written a function, which is not a smi. // We know that we have written a function, which is not a smi.
__ mov(r1, Operand(cp)); __ mov(r1, Operand(cp));
__ RecordWrite(r1, Operand(offset), r2, result_register()); __ 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, variable->index()));
// No write barrier since the_hole_value is in old space.
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} }
break; break;
case Slot::LOOKUP: { case Variable::LOOKUP: {
Comment cmnt(masm_, "[ Declaration");
__ mov(r2, Operand(variable->name())); __ 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 || ASSERT(mode == Variable::VAR ||
mode == Variable::CONST || mode == Variable::CONST ||
mode == Variable::LET); mode == Variable::LET);
@ -747,15 +771,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// Note: For variables we must not push an initial value (such as // Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we // 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value. // must not destroy the current value.
if (mode == Variable::CONST) { if (function != NULL) {
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
__ Push(cp, r2, r1, r0);
} else if (function != NULL) {
__ Push(cp, r2, r1); __ Push(cp, r2, r1);
// Push initial value for function declaration. // Push initial value for function declaration.
VisitForStackValue(function); VisitForStackValue(function);
} else if (mode == Variable::CONST || mode == Variable::LET) {
__ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
__ Push(cp, r2, r1, r0);
} else { } 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); __ Push(cp, r2, r1, r0);
} }
__ CallRuntime(Runtime::kDeclareContextSlot, 4); __ CallRuntime(Runtime::kDeclareContextSlot, 4);
@ -765,19 +789,16 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
} }
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
}
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals. // Call the runtime to declare the globals.
// The context is the first argument. // The context is the first argument.
__ mov(r2, Operand(pairs)); __ mov(r1, Operand(pairs));
__ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0))); __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
__ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); __ Push(cp, r1, r0);
__ Push(cp, r2, r1, r0); __ CallRuntime(Runtime::kDeclareGlobals, 3);
__ CallRuntime(Runtime::kDeclareGlobals, 4);
// Return value is ignored. // Return value is ignored.
} }
@ -1085,10 +1106,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
} }
void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
Slot* slot, TypeofState typeof_state,
TypeofState typeof_state, Label* slow) {
Label* slow) {
Register current = cp; Register current = cp;
Register next = r1; Register next = r1;
Register temp = r2; Register temp = r2;
@ -1135,7 +1155,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
} }
__ ldr(r0, GlobalObjectOperand()); __ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(slot->var()->name())); __ mov(r2, Operand(var->name()));
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET ? RelocInfo::CODE_TARGET
: RelocInfo::CODE_TARGET_CONTEXT; : RelocInfo::CODE_TARGET_CONTEXT;
@ -1144,15 +1164,14 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
} }
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
Slot* slot, Label* slow) {
Label* slow) { ASSERT(var->IsContextSlot());
ASSERT(slot->type() == Slot::CONTEXT);
Register context = cp; Register context = cp;
Register next = r3; Register next = r3;
Register temp = r4; 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->num_heap_slots() > 0) {
if (s->calls_eval()) { if (s->calls_eval()) {
// Check that extension is NULL. // Check that extension is NULL.
@ -1173,59 +1192,30 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
// This function is used only for loads, not stores, so it's safe to // 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 // return an cp-based operand (the write barrier cannot be allowed to
// destroy the cp register). // destroy the cp register).
return ContextOperand(context, slot->index()); return ContextOperand(context, var->index());
} }
void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
Slot* slot, TypeofState typeof_state,
TypeofState typeof_state, Label* slow,
Label* slow, Label* done) {
Label* done) {
// Generate fast-case code for variables that might be shadowed by // Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without // eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to // introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope // perform a runtime call for all variables in the scope
// containing the eval. // containing the eval.
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { if (var->mode() == Variable::DYNAMIC_GLOBAL) {
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done); __ jmp(done);
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); Variable* local = var->local_if_not_shadowed();
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow));
if (potential_slot != NULL) { if (local->mode() == Variable::CONST) {
// Generate fast case for locals that rewrite to slots. __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
__ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow)); __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
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);
}
}
} }
__ jmp(done);
} }
} }
@ -1235,52 +1225,60 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
SetSourcePosition(proxy->position()); SetSourcePosition(proxy->position());
Variable* var = proxy->var(); Variable* var = proxy->var();
// Three cases: non-this global variables, lookup slots, and all other // Three cases: global variables, lookup variables, and all other types of
// types of slots. // variables.
Slot* slot = var->AsSlot(); switch (var->location()) {
ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); case Variable::UNALLOCATED: {
Comment cmnt(masm_, "Global variable");
if (slot == NULL) { // Use inline caching. Variable name is passed in r2 and the global
Comment cmnt(masm_, "Global variable"); // object (receiver) in r0.
// Use inline caching. Variable name is passed in r2 and the global __ ldr(r0, GlobalObjectOperand());
// object (receiver) in r0. __ mov(r2, Operand(var->name()));
__ ldr(r0, GlobalObjectOperand()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
__ mov(r2, Operand(var->name())); __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); context()->Plug(r0);
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); break;
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); 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;
}
} else { case Variable::LOOKUP: {
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) Label done, slow;
? "Context slot" // Generate code for loading from variables potentially shadowed
: "Stack slot"); // by eval-introduced variables.
if (var->mode() == Variable::CONST) { EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
// Constants may be the hole value if they have not been initialized. __ bind(&slow);
// Unhole them. Comment cmnt(masm_, "Lookup variable");
MemOperand slot_operand = EmitSlotSearch(slot, r0); __ mov(r1, Operand(var->name()));
__ ldr(r0, slot_operand); __ Push(cp, r1); // Context and name.
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ cmp(r0, ip); __ bind(&done);
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
context()->Plug(r0); context()->Plug(r0);
} else {
context()->Plug(slot);
} }
} }
} }
@ -1814,14 +1812,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var, void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) { Token::Value op) {
ASSERT(var != NULL); if (var->IsUnallocated()) {
ASSERT(var->is_global() || var->AsSlot() != NULL); // Global var, const, or let.
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.
__ mov(r2, Operand(var->name())); __ mov(r2, Operand(var->name()));
__ ldr(r1, GlobalObjectOperand()); __ ldr(r1, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
@ -1830,67 +1822,83 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) { } else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function // Const initializers need a write barrier.
// scope. However, unlike var initializers, const initializers are able ASSERT(!var->IsParameter()); // No const parameters.
// to drill a hole to that function context, even from inside a 'with' if (var->IsStackLocal()) {
// context. We thus bypass the normal static scope lookup. Label skip;
Slot* slot = var->AsSlot(); __ ldr(r1, StackOperand(var));
Label skip; __ CompareRoot(r1, Heap::kTheHoleValueRootIndex);
switch (slot->type()) { __ b(ne, &skip);
case Slot::PARAMETER: __ str(result_register(), StackOperand(var));
// No const parameters. __ bind(&skip);
UNREACHABLE(); } else {
break; ASSERT(var->IsContextSlot() || var->IsLookupSlot());
case Slot::LOCAL: // Like var declarations, const declarations are hoisted to function
// Detect const reinitialization by checking for the hole value. // scope. However, unlike var initializers, const initializers are
__ ldr(r1, MemOperand(fp, SlotOffset(slot))); // able to drill a hole to that function context, even from inside a
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); // 'with' context. We thus bypass the normal static scope lookup for
__ cmp(r1, ip); // var->IsContextSlot().
__ b(ne, &skip); __ push(r0);
__ str(result_register(), MemOperand(fp, SlotOffset(slot))); __ mov(r0, Operand(var->name()));
break; __ Push(cp, r0); // Context and name.
case Slot::CONTEXT: __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
case Slot::LOOKUP:
__ push(r0);
__ mov(r0, Operand(slot->var()->name()));
__ Push(cp, r0); // Context and name.
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
break;
} }
__ bind(&skip);
} else if (var->mode() != Variable::CONST) { } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
// Perform the assignment for non-const variables. Const assignments // Non-initializing assignment to let variable needs a write barrier.
// are simply skipped. if (var->IsLookupSlot()) {
Slot* slot = var->AsSlot(); __ push(r0); // Value.
switch (slot->type()) { __ mov(r1, Operand(var->name()));
case Slot::PARAMETER: __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
case Slot::LOCAL: __ Push(cp, r1, r0); // Context, name, strict mode.
// Perform the assignment. __ CallRuntime(Runtime::kStoreContextSlot, 4);
__ str(result_register(), MemOperand(fp, SlotOffset(slot))); } else {
break; ASSERT(var->IsStackAllocated() || var->IsContextSlot());
Label assign;
case Slot::CONTEXT: { MemOperand location = VarOperand(var, r1);
MemOperand target = EmitSlotSearch(slot, r1); __ ldr(r3, location);
// Perform the assignment and issue the write barrier. __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
__ str(result_register(), target); __ 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. // RecordWrite may destroy all its register arguments.
__ mov(r3, result_register()); __ mov(r3, result_register());
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; int offset = Context::SlotOffset(var->index());
__ RecordWrite(r1, Operand(offset), r2, r3); __ RecordWrite(r1, Operand(offset), r2, r3);
break;
} }
}
case Slot::LOOKUP: } else if (var->mode() != Variable::CONST) {
// Call the runtime for the assignment. // Assignment to var or initializing assignment to let.
__ push(r0); // Value. if (var->IsStackAllocated() || var->IsContextSlot()) {
__ mov(r1, Operand(slot->var()->name())); MemOperand location = VarOperand(var, r1);
__ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); if (FLAG_debug_code && op == Token::INIT_LET) {
__ Push(cp, r1, r0); // Context, name, strict mode. // Check for an uninitialized let binding.
__ CallRuntime(Runtime::kStoreContextSlot, 4); __ ldr(r2, location);
break; __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
__ Check(eq, "Let binding re-initialization.");
}
// 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.
} }
@ -2100,8 +2108,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
int receiver_offset = 2 + info_->scope()->num_parameters(); int receiver_offset = 2 + info_->scope()->num_parameters();
__ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize)); __ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(r1); __ push(r1);
// Push the strict mode flag. // Push the strict mode flag. In harmony mode every eval call
__ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); // 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); __ push(r1);
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
@ -2118,10 +2131,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
#endif #endif
Comment cmnt(masm_, "[ Call"); Comment cmnt(masm_, "[ Call");
Expression* fun = expr->expression(); Expression* callee = expr->expression();
Variable* var = fun->AsVariableProxy()->AsVariable(); 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 // In a call to eval, we first call %ResolvePossiblyDirectEval to
// resolve the function we need to call and the receiver of the // resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given // call. Then we call the resolved function using the given
@ -2130,7 +2144,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
int arg_count = args->length(); int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder()); { PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(fun); VisitForStackValue(callee);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex); __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot. __ push(r2); // Reserved receiver slot.
@ -2144,11 +2158,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// in generated code. If we succeed, there is no need to perform a // in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system. // context lookup in the runtime system.
Label done; 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; Label slow;
EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
NOT_INSIDE_TYPEOF,
&slow);
// Push the function and resolve eval. // Push the function and resolve eval.
__ push(r0); __ push(r0);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@ -2156,14 +2169,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ bind(&slow); __ 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. // resolve eval.
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(r1); __ push(r1);
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); 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 // The runtime call returns a pair of values in r0 (function) and
// r1 (receiver). Touch up the stack with the right values. // r1 (receiver). Touch up the stack with the right values.
@ -2180,30 +2191,26 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Restore context register. // Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, r0); 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. // Push global object as receiver for the call IC.
__ ldr(r0, GlobalObjectOperand()); __ ldr(r0, GlobalObjectOperand());
__ push(r0); __ push(r0);
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (var != NULL && var->AsSlot() != NULL && } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
var->AsSlot()->type() == Slot::LOOKUP) {
// Call to a lookup slot (dynamically introduced variable). // Call to a lookup slot (dynamically introduced variable).
Label slow, done; Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder()); { PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed // Generate code for loading from variables potentially shadowed
// by eval-introduced variables. // by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(), EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
NOT_INSIDE_TYPEOF,
&slow,
&done);
} }
__ bind(&slow); __ bind(&slow);
// Call the runtime to find the function to call (returned in r0) // Call the runtime to find the function to call (returned in r0)
// and the object holding it (returned in edx). // and the object holding it (returned in edx).
__ push(context_register()); __ push(context_register());
__ mov(r2, Operand(var->name())); __ mov(r2, Operand(proxy->name()));
__ push(r2); __ push(r2);
__ CallRuntime(Runtime::kLoadContextSlot, 2); __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ Push(r0, r1); // Function, receiver. __ Push(r0, r1); // Function, receiver.
@ -2228,26 +2235,21 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// by LoadContextSlot. That object could be the hole if the // by LoadContextSlot. That object could be the hole if the
// receiver is implicitly the global object. // receiver is implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
} else if (fun->AsProperty() != NULL) { } else if (property != NULL) {
// Call to an object property. { PreservePositionScope scope(masm()->positions_recorder());
Property* prop = fun->AsProperty(); VisitForStackValue(property->obj());
Literal* key = prop->key()->AsLiteral(); }
if (key != NULL && key->handle()->IsSymbol()) { if (property->key()->IsPropertyName()) {
// Call to a named property, use call IC. EmitCallWithIC(expr,
{ PreservePositionScope scope(masm()->positions_recorder()); property->key()->AsLiteral()->handle(),
VisitForStackValue(prop->obj()); RelocInfo::CODE_TARGET);
}
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else { } else {
// Call to a keyed property. EmitKeyedCallWithIC(expr, property->key());
{ PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
EmitKeyedCallWithIC(expr, prop->key());
} }
} else { } else {
// Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder()); { PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(fun); VisitForStackValue(callee);
} }
// Load global receiver object. // Load global receiver object.
__ ldr(r1, GlobalObjectOperand()); __ ldr(r1, GlobalObjectOperand());
@ -3194,7 +3196,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
Label done, not_found; Label done, not_found;
// tmp now holds finger offset as a smi. // tmp now holds finger offset as a smi.
ASSERT(kSmiTag == 0 && kSmiTagSize == 1); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// r2 now holds finger offset as a smi. // r2 now holds finger offset as a smi.
__ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@ -3569,32 +3571,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) { switch (expr->op()) {
case Token::DELETE: { case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
Property* prop = expr->expression()->AsProperty(); Property* property = expr->expression()->AsProperty();
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (prop != NULL) { if (property != NULL) {
VisitForStackValue(prop->obj()); VisitForStackValue(property->obj());
VisitForStackValue(prop->key()); VisitForStackValue(property->key());
__ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
__ push(r1); __ push(r1);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(r0); 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 // 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()); ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
if (var->is_global()) { if (var->IsUnallocated()) {
__ ldr(r2, GlobalObjectOperand()); __ ldr(r2, GlobalObjectOperand());
__ mov(r1, Operand(var->name())); __ mov(r1, Operand(var->name()));
__ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
__ Push(r2, r1, r0); __ Push(r2, r1, r0);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(r0); context()->Plug(r0);
} else if (var->AsSlot() != NULL && } else if (var->IsStackAllocated() || var->IsContextSlot()) {
var->AsSlot()->type() != Slot::LOOKUP) {
// Result of deleting non-global, non-dynamic variables is false. // Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects. // The subexpression does not have side effects.
context()->Plug(false); context()->Plug(var->is_this());
} else { } else {
// Non-global variable. Call the runtime to try to delete from the // Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced. // context where the variable was introduced.
@ -3869,7 +3871,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ASSERT(!context()->IsEffect()); ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest()); ASSERT(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy(); 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"); Comment cmnt(masm_, "Global variable");
__ ldr(r0, GlobalObjectOperand()); __ ldr(r0, GlobalObjectOperand());
__ mov(r2, Operand(proxy->name())); __ mov(r2, Operand(proxy->name()));
@ -3879,15 +3881,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
__ Call(ic); __ Call(ic);
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
context()->Plug(r0); context()->Plug(r0);
} else if (proxy != NULL && } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
proxy->var()->AsSlot() != NULL &&
proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
Label done, slow; Label done, slow;
// Generate code for loading from variables potentially shadowed // Generate code for loading from variables potentially shadowed
// by eval-introduced variables. // by eval-introduced variables.
Slot* slot = proxy->var()->AsSlot(); EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
__ bind(&slow); __ bind(&slow);
__ mov(r0, Operand(proxy->name())); __ mov(r0, Operand(proxy->name()));
@ -4182,7 +4181,7 @@ void FullCodeGenerator::EnterFinallyBlock() {
// Cook return address in link register to stack (smi encoded Code* delta) // Cook return address in link register to stack (smi encoded Code* delta)
__ sub(r1, lr, Operand(masm_->CodeObject())); __ sub(r1, lr, Operand(masm_->CodeObject()));
ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(kSmiTag == 0);
__ add(r1, r1, Operand(r1)); // Convert to smi. __ add(r1, r1, Operand(r1)); // Convert to smi.
__ push(r1); __ push(r1);
} }
@ -4200,6 +4199,34 @@ void FullCodeGenerator::ExitFinallyBlock() {
} }
#undef __
#define __ ACCESS_MASM(masm())
FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
int* stack_depth,
int* context_length) {
// The macros used here must preserve the result register.
// Because the handler block contains the context of the finally
// code, we can restore it directly from there for the finally code
// rather than iteratively unwinding contexts via their previous
// links.
__ Drop(*stack_depth); // Down to the handler block.
if (*context_length > 0) {
// Restore the context to its dedicated register and the stack.
__ ldr(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
__ PopTryHandler();
__ bl(finally_entry_);
*stack_depth = 0;
*context_length = 0;
return previous_;
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

6
deps/v8/src/arm/ic-arm.cc

@ -337,7 +337,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
// Fast case: Do the load. // Fast case: Do the load.
__ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// The key is a smi. // The key is a smi.
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ ldr(scratch2, __ ldr(scratch2,
MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize)); MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
@ -370,7 +370,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
// Is the string a symbol? // Is the string a symbol?
// map: key map // map: key map
__ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
ASSERT(kSymbolTag != 0); STATIC_ASSERT(kSymbolTag != 0);
__ tst(hash, Operand(kIsSymbolMask)); __ tst(hash, Operand(kIsSymbolMask));
__ b(eq, not_symbol); __ b(eq, not_symbol);
} }
@ -1333,7 +1333,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
__ cmp(key, Operand(ip)); __ cmp(key, Operand(ip));
__ b(hs, &slow); __ b(hs, &slow);
// Calculate key + 1 as smi. // Calculate key + 1 as smi.
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(kSmiTag == 0);
__ add(r4, key, Operand(Smi::FromInt(1))); __ add(r4, key, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ b(&fast); __ b(&fast);

15
deps/v8/src/arm/lithium-codegen-arm.cc

@ -198,14 +198,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy any necessary parameters into the context. // Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters(); int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Variable* var = scope()->parameter(i);
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize; (num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack. // Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset)); __ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context. // Store it in the context.
__ mov(r1, Operand(Context::SlotOffset(slot->index()))); __ mov(r1, Operand(Context::SlotOffset(var->index())));
__ str(r0, MemOperand(cp, r1)); __ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved // Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid // registers, so we have to use two more registers to avoid
@ -3473,8 +3473,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the indirect string shape: slice or cons. // Dispatch on the indirect string shape: slice or cons.
Label cons_string; Label cons_string;
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
__ tst(result, Operand(kSlicedNotConsMask)); __ tst(result, Operand(kSlicedNotConsMask));
__ b(eq, &cons_string); __ b(eq, &cons_string);
@ -3511,7 +3509,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the encoding: ASCII or two-byte. // Dispatch on the encoding: ASCII or two-byte.
Label ascii_string; Label ascii_string;
STATIC_ASSERT(kAsciiStringTag != 0); STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ tst(result, Operand(kStringEncodingMask)); __ tst(result, Operand(kStringEncodingMask));
__ b(ne, &ascii_string); __ b(ne, &ascii_string);
@ -3759,7 +3758,7 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
LOperand* input = instr->InputAt(0); LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister() && input->Equals(instr->result())); ASSERT(input->IsRegister() && input->Equals(instr->result()));
if (instr->needs_check()) { if (instr->needs_check()) {
ASSERT(kHeapObjectTag == 1); STATIC_ASSERT(kHeapObjectTag == 1);
// If the input is a HeapObject, SmiUntag will set the carry flag. // If the input is a HeapObject, SmiUntag will set the carry flag.
__ SmiUntag(ToRegister(input), SetCC); __ SmiUntag(ToRegister(input), SetCC);
DeoptimizeIf(cs, instr->environment()); DeoptimizeIf(cs, instr->environment());
@ -3844,7 +3843,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
// The input was optimistically untagged; revert it. // The input was optimistically untagged; revert it.
// The carry flag is set when we reach this deferred code as we just executed // The carry flag is set when we reach this deferred code as we just executed
// SmiUntag(heap_object, SetCC) // SmiUntag(heap_object, SetCC)
ASSERT(kHeapObjectTag == 1); STATIC_ASSERT(kHeapObjectTag == 1);
__ adc(input_reg, input_reg, Operand(input_reg)); __ adc(input_reg, input_reg, Operand(input_reg));
// Heap number map check. // Heap number map check.

40
deps/v8/src/arm/macro-assembler-arm.cc

@ -1725,6 +1725,46 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
} }
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, void MacroAssembler::CompareObjectType(Register object,
Register map, Register map,
Register type_reg, Register type_reg,

10
deps/v8/src/arm/macro-assembler-arm.h

@ -532,6 +532,16 @@ class MacroAssembler: public Assembler {
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Label* gc_required); 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 // 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 // space is full and a scavenge is needed. All registers are clobbered also

2
deps/v8/src/arm/regexp-macro-assembler-arm.cc

@ -1049,7 +1049,7 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
MaybeObject* result = Execution::HandleStackGuardInterrupt(); MaybeObject* result = Execution::HandleStackGuardInterrupt();
if (*code_handle != re_code) { // Return address no longer valid if (*code_handle != re_code) { // Return address no longer valid
int delta = *code_handle - re_code; int delta = code_handle->address() - re_code->address();
// Overwrite the return address on the stack. // Overwrite the return address on the stack.
*return_address += delta; *return_address += delta;
} }

6
deps/v8/src/arm/stub-cache-arm.cc

@ -3497,7 +3497,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// We are not untagging smi key and instead work with it // We are not untagging smi key and instead work with it
// as if it was premultiplied by 2. // as if it was premultiplied by 2.
ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
Register value = r2; Register value = r2;
switch (elements_kind) { switch (elements_kind) {
@ -4147,7 +4147,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// Load the result and make sure it's not the hole. // Load the result and make sure it's not the hole.
__ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ add(r3, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ ldr(r4, __ ldr(r4,
MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
@ -4279,7 +4279,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
__ add(scratch, __ add(scratch,
elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ str(value_reg, __ str(value_reg,
MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize));
__ RecordWrite(scratch, __ RecordWrite(scratch,

63
deps/v8/src/array.js

@ -996,6 +996,9 @@ function ArrayFilter(f, receiver) {
if (!IS_FUNCTION(f)) { if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
}
// Pull out the length so that modifications to the length in the // Pull out the length so that modifications to the length in the
// loop will not affect the looping. // loop will not affect the looping.
var length = ToUint32(this.length); var length = ToUint32(this.length);
@ -1004,7 +1007,7 @@ function ArrayFilter(f, receiver) {
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = this[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in this) {
if (f.call(receiver, current, i, this)) { if (%_CallFunction(receiver, current, i, this, f)) {
result[result_length++] = current; result[result_length++] = current;
} }
} }
@ -1022,13 +1025,16 @@ function ArrayForEach(f, receiver) {
if (!IS_FUNCTION(f)) { if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
}
// Pull out the length so that modifications to the length in the // Pull out the length so that modifications to the length in the
// loop will not affect the looping. // loop will not affect the looping.
var length = TO_UINT32(this.length); var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = this[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in this) {
f.call(receiver, current, i, this); %_CallFunction(receiver, current, i, this, f);
} }
} }
} }
@ -1045,13 +1051,16 @@ function ArraySome(f, receiver) {
if (!IS_FUNCTION(f)) { if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
}
// Pull out the length so that modifications to the length in the // Pull out the length so that modifications to the length in the
// loop will not affect the looping. // loop will not affect the looping.
var length = TO_UINT32(this.length); var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = this[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in this) {
if (f.call(receiver, current, i, this)) return true; if (%_CallFunction(receiver, current, i, this, f)) return true;
} }
} }
return false; return false;
@ -1067,13 +1076,16 @@ function ArrayEvery(f, receiver) {
if (!IS_FUNCTION(f)) { if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
}
// Pull out the length so that modifications to the length in the // Pull out the length so that modifications to the length in the
// loop will not affect the looping. // loop will not affect the looping.
var length = TO_UINT32(this.length); var length = TO_UINT32(this.length);
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = this[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in this) {
if (!f.call(receiver, current, i, this)) return false; if (!%_CallFunction(receiver, current, i, this, f)) return false;
} }
} }
return true; return true;
@ -1088,6 +1100,9 @@ function ArrayMap(f, receiver) {
if (!IS_FUNCTION(f)) { if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]); throw MakeTypeError('called_non_callable', [ f ]);
} }
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
}
// Pull out the length so that modifications to the length in the // Pull out the length so that modifications to the length in the
// loop will not affect the looping. // loop will not affect the looping.
var length = TO_UINT32(this.length); var length = TO_UINT32(this.length);
@ -1096,7 +1111,7 @@ function ArrayMap(f, receiver) {
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var current = this[i]; var current = this[i];
if (!IS_UNDEFINED(current) || i in this) { if (!IS_UNDEFINED(current) || i in this) {
accumulator[i] = f.call(receiver, current, i, this); accumulator[i] = %_CallFunction(receiver, current, i, this, f);
} }
} }
%MoveArrayContents(accumulator, result); %MoveArrayContents(accumulator, result);
@ -1233,6 +1248,7 @@ function ArrayReduce(callback, current) {
if (!IS_FUNCTION(callback)) { if (!IS_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]); throw MakeTypeError('called_non_callable', [callback]);
} }
// Pull out the length so that modifications to the length in the // Pull out the length so that modifications to the length in the
// loop will not affect the looping. // loop will not affect the looping.
var length = ToUint32(this.length); var length = ToUint32(this.length);
@ -1249,10 +1265,11 @@ function ArrayReduce(callback, current) {
throw MakeTypeError('reduce_no_initial', []); throw MakeTypeError('reduce_no_initial', []);
} }
var receiver = %GetDefaultReceiver(callback);
for (; i < length; i++) { for (; i < length; i++) {
var element = this[i]; var element = this[i];
if (!IS_UNDEFINED(element) || i in this) { if (!IS_UNDEFINED(element) || i in this) {
current = callback.call(void 0, current, element, i, this); current = %_CallFunction(receiver, current, element, i, this, callback);
} }
} }
return current; return current;
@ -1280,10 +1297,11 @@ function ArrayReduceRight(callback, current) {
throw MakeTypeError('reduce_no_initial', []); throw MakeTypeError('reduce_no_initial', []);
} }
var receiver = %GetDefaultReceiver(callback);
for (; i >= 0; i--) { for (; i >= 0; i--) {
var element = this[i]; var element = this[i];
if (!IS_UNDEFINED(element) || i in this) { if (!IS_UNDEFINED(element) || i in this) {
current = callback.call(void 0, current, element, i, this); current = %_CallFunction(receiver, current, element, i, this, callback);
} }
} }
return current; return current;
@ -1296,12 +1314,13 @@ function ArrayIsArray(obj) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupArray() { function SetUpArray() {
// Setup non-enumerable constructor property on the Array.prototype %CheckIsBootstrapping();
// Set up non-enumerable constructor property on the Array.prototype
// object. // object.
%SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM); %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( InstallFunctions($Array, DONT_ENUM, $Array(
"isArray", ArrayIsArray "isArray", ArrayIsArray
)); ));
@ -1319,7 +1338,7 @@ function SetupArray() {
return f; 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. // set their names.
// Manipulate the length of some of the functions to meet // Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla. // expectations set by ECMA-262 or Mozilla.
@ -1350,19 +1369,13 @@ function SetupArray() {
%FinishArrayPrototypeSetup($Array.prototype); %FinishArrayPrototypeSetup($Array.prototype);
// The internal Array prototype doesn't need to be fancy, since it's never // 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 // exposed to user code.
// are necessary. // Adding only the functions that are actually used.
// The null __proto__ ensures that we never inherit any user created SetUpLockedPrototype(InternalArray, $Array(), $Array(
// getters or setters from, e.g., Object.prototype. "join", getFunction("join", ArrayJoin),
InternalArray.prototype.__proto__ = null; "pop", getFunction("pop", ArrayPop),
// Adding only the functions that are actually used, and a toString. "push", getFunction("push", ArrayPush)
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;
};
} }
SetUpArray();
SetupArray();

34
deps/v8/src/ast.cc

@ -36,20 +36,9 @@
namespace v8 { namespace v8 {
namespace internal { 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. // All the Accept member functions for each syntax tree node type.
void Slot::Accept(AstVisitor* v) { v->VisitSlot(this); }
#define DECL_ACCEPT(type) \ #define DECL_ACCEPT(type) \
void type::Accept(AstVisitor* v) { v->Visit##type(this); } void type::Accept(AstVisitor* v) { v->Visit##type(this); }
AST_NODE_LIST(DECL_ACCEPT) AST_NODE_LIST(DECL_ACCEPT)
@ -101,15 +90,6 @@ VariableProxy::VariableProxy(Isolate* isolate,
} }
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) { void VariableProxy::BindTo(Variable* var) {
ASSERT(var_ == NULL); // must be bound only once ASSERT(var_ == NULL); // must be bound only once
ASSERT(var != NULL); // must bind ASSERT(var != NULL); // must bind
@ -414,12 +394,6 @@ bool TargetCollector::IsInlineable() const {
} }
bool Slot::IsInlineable() const {
UNREACHABLE();
return false;
}
bool ForInStatement::IsInlineable() const { bool ForInStatement::IsInlineable() const {
return false; return false;
} }
@ -487,12 +461,6 @@ bool SharedFunctionInfoLiteral::IsInlineable() const {
} }
bool ValidLeftHandSideSentinel::IsInlineable() const {
UNREACHABLE();
return false;
}
bool ForStatement::IsInlineable() const { bool ForStatement::IsInlineable() const {
return (init() == NULL || init()->IsInlineable()) return (init() == NULL || init()->IsInlineable())
&& (cond() == NULL || cond()->IsInlineable()) && (cond() == NULL || cond()->IsInlineable())
@ -566,7 +534,7 @@ bool Conditional::IsInlineable() const {
bool VariableProxy::IsInlineable() const { bool VariableProxy::IsInlineable() const {
return var()->is_global() || var()->IsStackAllocated(); return var()->IsUnallocated() || var()->IsStackAllocated();
} }

134
deps/v8/src/ast.h

@ -134,6 +134,10 @@ class AstNode: public ZoneObject {
static const int kNoNumber = -1; static const int kNoNumber = -1;
static const int kFunctionEntryId = 2; // Using 0 could disguise errors. 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. // Override ZoneObject's new to count allocated AST nodes.
void* operator new(size_t size, Zone* zone) { void* operator new(size_t size, Zone* zone) {
@ -161,7 +165,6 @@ class AstNode: public ZoneObject {
virtual BreakableStatement* AsBreakableStatement() { return NULL; } virtual BreakableStatement* AsBreakableStatement() { return NULL; }
virtual IterationStatement* AsIterationStatement() { return NULL; } virtual IterationStatement* AsIterationStatement() { return NULL; }
virtual MaterializedLiteral* AsMaterializedLiteral() { 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. // True if the node is simple enough for us to inline calls containing it.
virtual bool IsInlineable() const = 0; virtual bool IsInlineable() const = 0;
@ -316,20 +319,6 @@ class Expression: public AstNode {
}; };
/**
* 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 { class BreakableStatement: public Statement {
public: public:
enum Type { enum Type {
@ -404,10 +393,14 @@ class Block: public BreakableStatement {
class Declaration: public AstNode { class Declaration: public AstNode {
public: public:
Declaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* fun) Declaration(VariableProxy* proxy,
Variable::Mode mode,
FunctionLiteral* fun,
Scope* scope)
: proxy_(proxy), : proxy_(proxy),
mode_(mode), mode_(mode),
fun_(fun) { fun_(fun),
scope_(scope) {
ASSERT(mode == Variable::VAR || ASSERT(mode == Variable::VAR ||
mode == Variable::CONST || mode == Variable::CONST ||
mode == Variable::LET); mode == Variable::LET);
@ -421,11 +414,15 @@ class Declaration: public AstNode {
Variable::Mode mode() const { return mode_; } Variable::Mode mode() const { return mode_; }
FunctionLiteral* fun() const { return fun_; } // may be NULL FunctionLiteral* fun() const { return fun_; } // may be NULL
virtual bool IsInlineable() const; virtual bool IsInlineable() const;
Scope* scope() const { return scope_; }
private: private:
VariableProxy* proxy_; VariableProxy* proxy_;
Variable::Mode mode_; Variable::Mode mode_;
FunctionLiteral* fun_; FunctionLiteral* fun_;
// Nested scope from which the declaration originated.
Scope* scope_;
}; };
@ -1114,9 +1111,6 @@ class VariableProxy: public Expression {
DECLARE_NODE_TYPE(VariableProxy) DECLARE_NODE_TYPE(VariableProxy)
// Type testing & conversion
Variable* AsVariable() { return (this == NULL) ? NULL : var_; }
virtual bool IsValidLeftHandSide() { virtual bool IsValidLeftHandSide() {
return var_ == NULL ? true : var_->IsValidLeftHandSide(); return var_ == NULL ? true : var_->IsValidLeftHandSide();
} }
@ -1133,10 +1127,7 @@ class VariableProxy: public Expression {
return !is_this() && name().is_identical_to(n); return !is_this() && name().is_identical_to(n);
} }
bool IsArguments() { bool IsArguments() { return var_ != NULL && var_->is_arguments(); }
Variable* variable = AsVariable();
return (variable == NULL) ? false : variable->is_arguments();
}
Handle<String> name() const { return name_; } Handle<String> name() const { return name_; }
Variable* var() const { return var_; } Variable* var() const { return var_; }
@ -1162,73 +1153,11 @@ class VariableProxy: public Expression {
bool is_this, bool is_this,
bool inside_with, bool inside_with,
int position = RelocInfo::kNoPosition); int position = RelocInfo::kNoPosition);
VariableProxy(Isolate* isolate, bool is_this);
friend class Scope; 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 { class Property: public Expression {
public: public:
Property(Isolate* isolate, Property(Isolate* isolate,
@ -1337,36 +1266,6 @@ class Call: public Expression {
}; };
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 { class CallNew: public Expression {
public: public:
CallNew(Isolate* isolate, CallNew(Isolate* isolate,
@ -2239,9 +2138,6 @@ class AstVisitor BASE_EMBEDDED {
void SetStackOverflow() { stack_overflow_ = true; } void SetStackOverflow() { stack_overflow_ = true; }
void ClearStackOverflow() { stack_overflow_ = false; } void ClearStackOverflow() { stack_overflow_ = false; }
// Nodes not appearing in the AST, including slots.
virtual void VisitSlot(Slot* node) { UNREACHABLE(); }
// Individual AST nodes. // Individual AST nodes.
#define DEF_VISIT(type) \ #define DEF_VISIT(type) \
virtual void Visit##type(type* node) = 0; virtual void Visit##type(type* node) = 0;

20
deps/v8/src/bootstrapper.cc

@ -350,7 +350,14 @@ static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
prototype, prototype,
call_code, call_code,
is_ecma_native); 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) { if (is_ecma_native) {
function->shared()->set_instance_class_name(*symbol); function->shared()->set_instance_class_name(*symbol);
} }
@ -1160,7 +1167,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
{ {
// Setup the call-as-function delegate. // Set up the call-as-function delegate.
Handle<Code> code = Handle<Code> code =
Handle<Code>(isolate->builtins()->builtin( Handle<Code>(isolate->builtins()->builtin(
Builtins::kHandleApiCallAsFunction)); Builtins::kHandleApiCallAsFunction));
@ -1172,7 +1179,7 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
} }
{ {
// Setup the call-as-constructor delegate. // Set up the call-as-constructor delegate.
Handle<Code> code = Handle<Code> code =
Handle<Code>(isolate->builtins()->builtin( Handle<Code>(isolate->builtins()->builtin(
Builtins::kHandleApiCallAsConstructor)); Builtins::kHandleApiCallAsConstructor));
@ -1192,15 +1199,15 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
void Genesis::InitializeExperimentalGlobal() { void Genesis::InitializeExperimentalGlobal() {
Isolate* isolate = this->isolate();
Handle<JSObject> global = Handle<JSObject>(global_context()->global()); Handle<JSObject> global = Handle<JSObject>(global_context()->global());
// TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no // TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
// longer need to live behind a flag, so WeakMap gets added to the snapshot. // longer need to live behind a flag, so WeakMap gets added to the snapshot.
if (FLAG_harmony_weakmaps) { // -- W e a k M a p if (FLAG_harmony_weakmaps) { // -- W e a k M a p
Handle<JSObject> prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize, InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
isolate->initial_object_prototype(), prototype, Builtins::kIllegal, true);
Builtins::kIllegal, true);
} }
} }
@ -1677,7 +1684,6 @@ bool Genesis::InstallNatives() {
global_context()->set_regexp_result_map(*initial_map); global_context()->set_regexp_result_map(*initial_map);
} }
#ifdef DEBUG #ifdef DEBUG
builtins->Verify(); builtins->Verify();
#endif #endif

6
deps/v8/src/checks.h

@ -251,9 +251,9 @@ template <> class StaticAssertion<true> { };
// actually causes each use to introduce a new defined type with a // actually causes each use to introduce a new defined type with a
// name depending on the source line. // name depending on the source line.
template <int> class StaticAssertionHelper { }; template <int> class StaticAssertionHelper { };
#define STATIC_CHECK(test) \ #define STATIC_CHECK(test) \
typedef \ typedef \
StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>(test)>)> \ StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>((test))>)> \
SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__) SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)

11
deps/v8/src/contexts.cc

@ -87,13 +87,15 @@ void Context::set_global_proxy(JSObject* object) {
Handle<Object> Context::Lookup(Handle<String> name, Handle<Object> Context::Lookup(Handle<String> name,
ContextLookupFlags flags, ContextLookupFlags flags,
int* index_, int* index_,
PropertyAttributes* attributes) { PropertyAttributes* attributes,
BindingFlags* binding_flags) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
Handle<Context> context(this, isolate); Handle<Context> context(this, isolate);
bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0; bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
*index_ = -1; *index_ = -1;
*attributes = ABSENT; *attributes = ABSENT;
*binding_flags = MISSING_BINDING;
if (FLAG_trace_contexts) { if (FLAG_trace_contexts) {
PrintF("Context::Lookup("); PrintF("Context::Lookup(");
@ -118,6 +120,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
} }
*index_ = Context::THROWN_OBJECT_INDEX; *index_ = Context::THROWN_OBJECT_INDEX;
*attributes = NONE; *attributes = NONE;
*binding_flags = MUTABLE_IS_INITIALIZED;
return context; return context;
} }
} else { } else {
@ -180,11 +183,16 @@ Handle<Object> Context::Lookup(Handle<String> name,
switch (mode) { switch (mode) {
case Variable::INTERNAL: // Fall through. case Variable::INTERNAL: // Fall through.
case Variable::VAR: case Variable::VAR:
*attributes = NONE;
*binding_flags = MUTABLE_IS_INITIALIZED;
break;
case Variable::LET: case Variable::LET:
*attributes = NONE; *attributes = NONE;
*binding_flags = MUTABLE_CHECK_INITIALIZED;
break; break;
case Variable::CONST: case Variable::CONST:
*attributes = READ_ONLY; *attributes = READ_ONLY;
*binding_flags = IMMUTABLE_CHECK_INITIALIZED;
break; break;
case Variable::DYNAMIC: case Variable::DYNAMIC:
case Variable::DYNAMIC_GLOBAL: case Variable::DYNAMIC_GLOBAL:
@ -207,6 +215,7 @@ Handle<Object> Context::Lookup(Handle<String> name,
} }
*index_ = index; *index_ = index;
*attributes = READ_ONLY; *attributes = READ_ONLY;
*binding_flags = IMMUTABLE_IS_INITIALIZED;
return context; return context;
} }
} }

31
deps/v8/src/contexts.h

@ -44,6 +44,30 @@ enum ContextLookupFlags {
}; };
// ES5 10.2 defines lexical environments with mutable and immutable bindings.
// Immutable bindings have two states, initialized and uninitialized, and
// their state is changed by the InitializeImmutableBinding method.
//
// The harmony proposal for block scoped bindings also introduces the
// uninitialized state for mutable bindings. A 'let' declared variable
// is a mutable binding that is created uninitalized upon activation of its
// lexical environment and it is initialized when evaluating its declaration
// statement. Var declared variables are mutable bindings that are
// immediately initialized upon creation. The BindingFlags enum represents
// information if a binding has definitely been initialized. 'const' declared
// variables are created as uninitialized immutable bindings.
// In harmony mode accessing an uninitialized binding produces a reference
// error.
enum BindingFlags {
MUTABLE_IS_INITIALIZED,
MUTABLE_CHECK_INITIALIZED,
IMMUTABLE_IS_INITIALIZED,
IMMUTABLE_CHECK_INITIALIZED,
MISSING_BINDING
};
// Heap-allocated activation contexts. // Heap-allocated activation contexts.
// //
// Contexts are implemented as FixedArray objects; the Context // Contexts are implemented as FixedArray objects; the Context
@ -351,8 +375,11 @@ class Context: public FixedArray {
// 4) index_ < 0 && result.is_null(): // 4) index_ < 0 && result.is_null():
// there was no context found with the corresponding property. // there was no context found with the corresponding property.
// attributes == ABSENT. // attributes == ABSENT.
Handle<Object> Lookup(Handle<String> name, ContextLookupFlags flags, Handle<Object> Lookup(Handle<String> name,
int* index_, PropertyAttributes* attributes); ContextLookupFlags flags,
int* index_,
PropertyAttributes* attributes,
BindingFlags* binding_flags);
// Determine if a local variable with the given name exists in a // Determine if a local variable with the given name exists in a
// context. Do not consider context extension objects. This is // context. Do not consider context extension objects. This is

4
deps/v8/src/conversions.h

@ -45,14 +45,14 @@ namespace internal {
const int kMaxSignificantDigits = 772; 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) return (x >= '0' && x <= '9' && x < '0' + radix)
|| (radix > 10 && x >= 'a' && x < 'a' + radix - 10) || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
|| (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; return negative ? -0.0 : 0.0;
} }

14
deps/v8/src/d8.cc

@ -176,8 +176,8 @@ bool Shell::ExecuteString(Handle<String> source,
// If all went well and the result wasn't undefined then print // If all went well and the result wasn't undefined then print
// the returned value. // the returned value.
v8::String::Utf8Value str(result); v8::String::Utf8Value str(result);
const char* cstr = ToCString(str); fwrite(*str, sizeof(**str), str.length(), stdout);
printf("%s\n", cstr); printf("\n");
} }
return true; return true;
} }
@ -678,12 +678,12 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
FunctionTemplate::New(PixelArray)); FunctionTemplate::New(PixelArray));
#ifdef LIVE_OBJECT_LIST #ifdef LIVE_OBJECT_LIST
global_template->Set(String::New("lol_is_enabled"), Boolean::New(true)); global_template->Set(String::New("lol_is_enabled"), True());
#else #else
global_template->Set(String::New("lol_is_enabled"), Boolean::New(false)); global_template->Set(String::New("lol_is_enabled"), False());
#endif #endif
#ifndef V8_SHARED #if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
Handle<ObjectTemplate> os_templ = ObjectTemplate::New(); Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
AddOSMethods(os_templ); AddOSMethods(os_templ);
global_template->Set(String::New("os"), os_templ); global_template->Set(String::New("os"), os_templ);
@ -864,7 +864,7 @@ Handle<String> Shell::ReadFile(const char* name) {
void Shell::RunShell() { void Shell::RunShell() {
Locker locker; Locker locker;
Context::Scope context_scope(evaluation_context_); Context::Scope context_scope(evaluation_context_);
HandleScope handle_scope; HandleScope outer_scope;
Handle<String> name = String::New("(d8)"); Handle<String> name = String::New("(d8)");
#ifndef V8_SHARED #ifndef V8_SHARED
LineEditor* editor = LineEditor::Get(); LineEditor* editor = LineEditor::Get();
@ -877,6 +877,7 @@ void Shell::RunShell() {
i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt); i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
if (input.is_empty()) break; if (input.is_empty()) break;
editor->AddHistory(*input); editor->AddHistory(*input);
HandleScope inner_scope;
ExecuteString(String::New(*input), name, true, true); ExecuteString(String::New(*input), name, true, true);
} }
editor->Close(); editor->Close();
@ -887,6 +888,7 @@ void Shell::RunShell() {
char buffer[kBufferSize]; char buffer[kBufferSize];
printf("%s", Shell::kPrompt); printf("%s", Shell::kPrompt);
if (fgets(buffer, kBufferSize, stdin) == NULL) break; if (fgets(buffer, kBufferSize, stdin) == NULL) break;
HandleScope inner_scope;
ExecuteString(String::New(buffer), name, true, true); ExecuteString(String::New(buffer), name, true, true);
} }
#endif // V8_SHARED #endif // V8_SHARED

2
deps/v8/src/d8.js

@ -1786,7 +1786,7 @@ function decodeLolInfoResponse(body) {
function decodeLolListResponse(body, title) { function decodeLolListResponse(body, title) {
var result; var result;
var total_count = body.count; var total_count = body.count;
var total_size = body.size; var total_size = body.size;

11
deps/v8/src/date.js

@ -1048,18 +1048,19 @@ function ResetDateCache() {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupDate() { function SetUpDate() {
// Setup non-enumerable properties of the Date object itself. %CheckIsBootstrapping();
// Set up non-enumerable properties of the Date object itself.
InstallFunctions($Date, DONT_ENUM, $Array( InstallFunctions($Date, DONT_ENUM, $Array(
"UTC", DateUTC, "UTC", DateUTC,
"parse", DateParse, "parse", DateParse,
"now", DateNow "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); %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. // set their names.
InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array( InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
"toString", DateToString, "toString", DateToString,
@ -1111,4 +1112,4 @@ function SetupDate() {
)); ));
} }
SetupDate(); SetUpDate();

1
deps/v8/src/elements.cc

@ -590,7 +590,6 @@ ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
default: default:
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
break;
} }
} }

6
deps/v8/src/extensions/externalize-string-extension.cc

@ -133,9 +133,11 @@ v8::Handle<v8::Value> ExternalizeStringExtension::IsAscii(
void ExternalizeStringExtension::Register() { 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( static v8::DeclareExtension externalize_extension_declaration(
&externalize_extension); externalize_extension);
} }
} } // namespace v8::internal } } // namespace v8::internal

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

@ -190,9 +190,9 @@ void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
void BreakableStatementChecker::VisitAssignment(Assignment* expr) { void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
// If assigning to a property (including a global property) the assignment is // If assigning to a property (including a global property) the assignment is
// breakable. // breakable.
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); VariableProxy* proxy = expr->target()->AsVariableProxy();
Property* prop = expr->target()->AsProperty(); Property* prop = expr->target()->AsProperty();
if (prop != NULL || (var != NULL && var->is_global())) { if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) {
is_breakable_ = true; is_breakable_ = true;
return; return;
} }
@ -395,26 +395,6 @@ void FullCodeGenerator::RecordStackCheck(int ast_id) {
} }
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) { bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
// Inline smi case inside loops, but not division and modulo which // Inline smi case inside loops, but not division and modulo which
// are too complicated and take up too much space. // are too complicated and take up too much space.
@ -529,34 +509,21 @@ void FullCodeGenerator::DoTest(const TestContext* context) {
void FullCodeGenerator::VisitDeclarations( void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) { ZoneList<Declaration*>* declarations) {
int length = declarations->length(); int length = declarations->length();
int globals = 0; int global_count = 0;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Declaration* decl = declarations->at(i); Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var(); EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count);
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++;
}
} }
// Compute array of global variable and function declarations. // Batch declare global functions and variables.
// Do nothing in case of no declared global functions or variables. if (global_count > 0) {
if (globals > 0) {
Handle<FixedArray> array = 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++) { for (int j = 0, i = 0; i < length; i++) {
Declaration* decl = declarations->at(i); Declaration* decl = declarations->at(i);
Variable* var = decl->proxy()->var(); 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())); array->set(j++, *(var->name()));
if (decl->fun() == NULL) { if (decl->fun() == NULL) {
if (var->mode() == Variable::CONST) { if (var->mode() == Variable::CONST) {
@ -578,12 +545,21 @@ void FullCodeGenerator::VisitDeclarations(
} }
} }
// Invoke the platform-dependent code generator to do the actual // Invoke the platform-dependent code generator to do the actual
// declaration the global variables and functions. // declaration the global functions and variables.
DeclareGlobals(array); 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) { void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
CodeGenerator::RecordPositions(masm_, fun->start_position()); CodeGenerator::RecordPositions(masm_, fun->start_position());
} }
@ -842,10 +818,11 @@ void FullCodeGenerator::VisitInCurrentContext(Expression* expr) {
void FullCodeGenerator::VisitBlock(Block* stmt) { void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block"); Comment cmnt(masm_, "[ Block");
Breakable nested_statement(this, stmt); NestedBlock nested_block(this, stmt);
SetStatementPosition(stmt); SetStatementPosition(stmt);
Scope* saved_scope = scope(); Scope* saved_scope = scope();
// Push a block context when entering a block with block scoped variables.
if (stmt->block_scope() != NULL) { if (stmt->block_scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context"); { Comment cmnt(masm_, "[ Extend block context");
scope_ = stmt->block_scope(); scope_ = stmt->block_scope();
@ -862,8 +839,16 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
VisitStatements(stmt->statements()); VisitStatements(stmt->statements());
scope_ = saved_scope; scope_ = saved_scope;
__ bind(nested_statement.break_label()); __ bind(nested_block.break_label());
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 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());
}
} }
@ -1336,25 +1321,6 @@ void FullCodeGenerator::VisitThrow(Throw* expr) {
} }
FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
int* stack_depth,
int* context_length) {
// The macros used here must preserve the result register.
__ Drop(*stack_depth);
__ PopTryHandler();
*stack_depth = 0;
Register context = FullCodeGenerator::context_register();
while (*context_length > 0) {
codegen_->LoadContextField(context, Context::PREVIOUS_INDEX);
--(*context_length);
}
__ Call(finally_entry_);
return previous_;
}
FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit( FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
int* stack_depth, int* stack_depth,
int* context_length) { int* context_length) {

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

@ -191,6 +191,22 @@ class FullCodeGenerator: public AstVisitor {
Label continue_label_; 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. // The try block of a try/catch statement.
class TryCatch : public NestedStatement { class TryCatch : public NestedStatement {
public: public:
@ -288,10 +304,6 @@ class FullCodeGenerator: public AstVisitor {
// with a GC-safe value. // with a GC-safe value.
void ClearAccumulator(); 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 // Determine whether or not to inline the smi case for the given
// operation. // operation.
bool ShouldInlineSmiCase(Token::Value op); bool ShouldInlineSmiCase(Token::Value op);
@ -321,13 +333,29 @@ class FullCodeGenerator: public AstVisitor {
Label* fall_through); Label* fall_through);
#endif // V8_TARGET_ARCH_MIPS #endif // V8_TARGET_ARCH_MIPS
void Move(Slot* dst, Register source, Register scratch1, Register scratch2); // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
void Move(Register dst, Slot* source); // a register. Emits a context chain walk if if necessary (so does
// SetVar) so avoid calling both on the same variable.
// Return an operand used to read/write to a known (ie, non-LOOKUP) slot. void GetVar(Register destination, Variable* var);
// May emit code to traverse the context chain, destroying the scratch
// register. // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable. If it's in
MemOperand EmitSlotSearch(Slot* slot, Register scratch); // 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 // Forward the bailout responsibility for the given expression to
// the next child visited (which must be in a test context). // the next child visited (which must be in a test context).
@ -358,6 +386,7 @@ class FullCodeGenerator: public AstVisitor {
void VisitDeclarations(ZoneList<Declaration*>* declarations); void VisitDeclarations(ZoneList<Declaration*>* declarations);
void DeclareGlobals(Handle<FixedArray> pairs); void DeclareGlobals(Handle<FixedArray> pairs);
int DeclareGlobalsFlags();
// Try to perform a comparison as a fast inlined literal compare if // Try to perform a comparison as a fast inlined literal compare if
// the operands allow it. Returns true if the compare operations // the operands allow it. Returns true if the compare operations
@ -402,9 +431,10 @@ class FullCodeGenerator: public AstVisitor {
// Platform-specific code for a variable, constant, or function // Platform-specific code for a variable, constant, or function
// declaration. Functions have an initial value. // declaration. Functions have an initial value.
void EmitDeclaration(Variable* variable, void EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function); FunctionLiteral* function,
int* global_count);
// Platform-specific code for checking the stack limit at the back edge of // Platform-specific code for checking the stack limit at the back edge of
// a loop. // a loop.
@ -435,14 +465,14 @@ class FullCodeGenerator: public AstVisitor {
#undef EMIT_INLINE_RUNTIME_CALL #undef EMIT_INLINE_RUNTIME_CALL
// Platform-specific code for loading variables. // Platform-specific code for loading variables.
void EmitLoadGlobalSlotCheckExtensions(Slot* slot, void EmitLoadGlobalCheckExtensions(Variable* var,
TypeofState typeof_state, TypeofState typeof_state,
Label* slow); Label* slow);
MemOperand ContextSlotOperandCheckExtensions(Slot* slot, Label* slow); MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
void EmitDynamicLoadFromSlotFastCase(Slot* slot, void EmitDynamicLookupFastCase(Variable* var,
TypeofState typeof_state, TypeofState typeof_state,
Label* slow, Label* slow,
Label* done); Label* done);
void EmitVariableLoad(VariableProxy* proxy); void EmitVariableLoad(VariableProxy* proxy);
enum ResolveEvalFlag { enum ResolveEvalFlag {
@ -555,6 +585,7 @@ class FullCodeGenerator: public AstVisitor {
Handle<Script> script() { return info_->script(); } Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); } bool is_eval() { return info_->is_eval(); }
bool is_native() { return info_->is_native(); }
bool is_strict_mode() { return function()->strict_mode(); } bool is_strict_mode() { return function()->strict_mode(); }
StrictModeFlag strict_mode_flag() { StrictModeFlag strict_mode_flag() {
return is_strict_mode() ? kStrictMode : kNonStrictMode; return is_strict_mode() ? kStrictMode : kNonStrictMode;
@ -618,11 +649,11 @@ class FullCodeGenerator: public AstVisitor {
// this expression context. // this expression context.
virtual void Plug(bool flag) const = 0; virtual void Plug(bool flag) const = 0;
// Emit code to convert a pure value (in a register, slot, as a literal, // Emit code to convert a pure value (in a register, known variable
// or on top of the stack) into the result expected according to this // location, as a literal, or on top of the stack) into the result
// expression context. // expected according to this expression context.
virtual void Plug(Register reg) const = 0; 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(Handle<Object> lit) const = 0;
virtual void Plug(Heap::RootListIndex index) const = 0; virtual void Plug(Heap::RootListIndex index) const = 0;
virtual void PlugTOS() const = 0; virtual void PlugTOS() const = 0;
@ -680,7 +711,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const; virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const; virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) 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(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const; virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const; virtual void PlugTOS() const;
@ -703,7 +734,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const; virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const; virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) 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(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const; virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const; virtual void PlugTOS() const;
@ -744,7 +775,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const; virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const; virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) 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(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const; virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const; virtual void PlugTOS() const;
@ -774,7 +805,7 @@ class FullCodeGenerator: public AstVisitor {
virtual void Plug(bool flag) const; virtual void Plug(bool flag) const;
virtual void Plug(Register reg) const; virtual void Plug(Register reg) const;
virtual void Plug(Label* materialize_true, Label* materialize_false) 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(Handle<Object> lit) const;
virtual void Plug(Heap::RootListIndex) const; virtual void Plug(Heap::RootListIndex) const;
virtual void PlugTOS() const; virtual void PlugTOS() const;

84
deps/v8/src/heap.cc

@ -81,14 +81,14 @@ Heap::Heap()
reserved_semispace_size_(16*MB), reserved_semispace_size_(16*MB),
max_semispace_size_(16*MB), max_semispace_size_(16*MB),
initial_semispace_size_(1*MB), initial_semispace_size_(1*MB),
max_old_generation_size_(1*GB), max_old_generation_size_(1400*MB),
max_executable_size_(256*MB), max_executable_size_(256*MB),
code_range_size_(512*MB), code_range_size_(512*MB),
#else #else
reserved_semispace_size_(8*MB), reserved_semispace_size_(8*MB),
max_semispace_size_(8*MB), max_semispace_size_(8*MB),
initial_semispace_size_(512*KB), initial_semispace_size_(512*KB),
max_old_generation_size_(512*MB), max_old_generation_size_(700*MB),
max_executable_size_(128*MB), max_executable_size_(128*MB),
code_range_size_(0), code_range_size_(0),
#endif #endif
@ -842,6 +842,7 @@ void Heap::MarkCompactPrologue(bool is_compacting) {
isolate_->keyed_lookup_cache()->Clear(); isolate_->keyed_lookup_cache()->Clear();
isolate_->context_slot_cache()->Clear(); isolate_->context_slot_cache()->Clear();
isolate_->descriptor_lookup_cache()->Clear(); isolate_->descriptor_lookup_cache()->Clear();
StringSplitCache::Clear(string_split_cache());
isolate_->compilation_cache()->MarkCompactPrologue(); isolate_->compilation_cache()->MarkCompactPrologue();
@ -2223,6 +2224,13 @@ bool Heap::CreateInitialObjects() {
} }
set_single_character_string_cache(FixedArray::cast(obj)); 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. // Allocate cache for external strings pointing to native source code.
{ MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount()); { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
if (!maybe_obj->ToObject(&obj)) return false; if (!maybe_obj->ToObject(&obj)) return false;
@ -2248,6 +2256,75 @@ bool Heap::CreateInitialObjects() {
} }
Object* StringSplitCache::Lookup(
FixedArray* cache, String* string, String* pattern) {
if (!string->IsSymbol() || !pattern->IsSymbol()) return Smi::FromInt(0);
uintptr_t hash = string->Hash();
uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) &
~(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;
uintptr_t hash = string->Hash();
array->set_map(heap->fixed_cow_array_map());
uintptr_t index = ((hash & (kStringSplitCacheSize - 1)) &
~(kArrayEntriesPerCacheEntry - 1));
if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
cache->set(index + kStringOffset, string);
cache->set(index + kPatternOffset, pattern);
cache->set(index + kArrayOffset, array);
return;
}
uintptr_t index2 =
((index + kArrayEntriesPerCacheEntry) & (kStringSplitCacheSize - 1));
if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
cache->set(index2 + kStringOffset, string);
cache->set(index2 + kPatternOffset, pattern);
cache->set(index2 + kArrayOffset, array);
return;
}
cache->set(index2 + kStringOffset, Smi::FromInt(0));
cache->set(index2 + kPatternOffset, Smi::FromInt(0));
cache->set(index2 + kArrayOffset, Smi::FromInt(0));
cache->set(index + kStringOffset, string);
cache->set(index + kPatternOffset, pattern);
cache->set(index + kArrayOffset, array);
if (array->length() < 100) { // Limit how many new symbols we want to make.
for (int i = 0; i < array->length(); i++) {
String* str = String::cast(array->get(i));
Object* symbol;
MaybeObject* maybe_symbol = heap->LookupSymbol(str);
if (maybe_symbol->ToObject(&symbol)) {
array->set(i, symbol);
}
}
}
}
void StringSplitCache::Clear(FixedArray* cache) {
for (int i = 0; i < kStringSplitCacheSize; i++) {
cache->set(i, Smi::FromInt(0));
}
}
MaybeObject* Heap::InitializeNumberStringCache() { MaybeObject* Heap::InitializeNumberStringCache() {
// Compute the size of the number string cache based on the max heap size. // Compute the size of the number string cache based on the max heap size.
// max_semispace_size_ == 512 KB => number_string_cache_size = 32. // max_semispace_size_ == 512 KB => number_string_cache_size = 32.
@ -4085,10 +4162,9 @@ MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
SerializedScopeInfo* scope_info) { SerializedScopeInfo* scope_info) {
Object* result; Object* result;
{ MaybeObject* maybe_result = { MaybeObject* maybe_result =
AllocateFixedArray(scope_info->NumberOfContextSlots()); AllocateFixedArrayWithHoles(scope_info->NumberOfContextSlots());
if (!maybe_result->ToObject(&result)) return maybe_result; if (!maybe_result->ToObject(&result)) return maybe_result;
} }
// TODO(keuchel): properly initialize context slots.
Context* context = reinterpret_cast<Context*>(result); Context* context = reinterpret_cast<Context*>(result);
context->set_map(block_context_map()); context->set_map(block_context_map());
context->set_closure(function); context->set_closure(function);

25
deps/v8/src/heap.h

@ -77,6 +77,7 @@ inline Heap* _inline_get_heap_();
V(Object, instanceof_cache_map, InstanceofCacheMap) \ V(Object, instanceof_cache_map, InstanceofCacheMap) \
V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \ V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \ V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
V(FixedArray, string_split_cache, StringSplitCache) \
V(Object, termination_exception, TerminationException) \ V(Object, termination_exception, TerminationException) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \ V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \ V(ByteArray, empty_byte_array, EmptyByteArray) \
@ -225,8 +226,7 @@ inline Heap* _inline_get_heap_();
V(closure_symbol, "(closure)") \ V(closure_symbol, "(closure)") \
V(use_strict, "use strict") \ V(use_strict, "use strict") \
V(dot_symbol, ".") \ V(dot_symbol, ".") \
V(anonymous_function_symbol, "(anonymous function)") \ V(anonymous_function_symbol, "(anonymous function)")
V(block_scope_symbol, ".block")
// Forward declarations. // Forward declarations.
class GCTracer; class GCTracer;
@ -2177,6 +2177,27 @@ class GCTracer BASE_EMBEDDED {
}; };
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 { class TranscendentalCache {
public: public:
enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches}; enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches};

18
deps/v8/src/hydrogen-instructions.cc

@ -425,7 +425,7 @@ void HValue::PrintRangeTo(StringStream* stream) {
void HValue::PrintChangesTo(StringStream* stream) { void HValue::PrintChangesTo(StringStream* stream) {
int changes_flags = (flags() & HValue::ChangesFlagsMask()); int changes_flags = ChangesFlags();
if (changes_flags == 0) return; if (changes_flags == 0) return;
stream->Add(" changes["); stream->Add(" changes[");
if (changes_flags == AllSideEffects()) { if (changes_flags == AllSideEffects()) {
@ -512,9 +512,7 @@ void HInstruction::PrintTo(StringStream* stream) {
void HInstruction::PrintMnemonicTo(StringStream* stream) { void HInstruction::PrintMnemonicTo(StringStream* stream) {
stream->Add("%s", Mnemonic()); stream->Add("%s ", Mnemonic());
if (HasSideEffects()) stream->Add("*");
stream->Add(" ");
} }
@ -791,6 +789,13 @@ void HChange::PrintDataTo(StringStream* stream) {
} }
void HJSArrayLength::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
stream->Add(" ");
typecheck()->PrintNameTo(stream);
}
HValue* HCheckInstanceType::Canonicalize() { HValue* HCheckInstanceType::Canonicalize() {
if (check_ == IS_STRING && if (check_ == IS_STRING &&
!value()->type().IsUninitialized() && !value()->type().IsUninitialized() &&
@ -1020,11 +1025,14 @@ void HPhi::PrintTo(StringStream* stream) {
value->PrintNameTo(stream); value->PrintNameTo(stream);
stream->Add(" "); stream->Add(" ");
} }
stream->Add(" uses%d_%di_%dd_%dt]", stream->Add(" uses%d_%di_%dd_%dt",
UseCount(), UseCount(),
int32_non_phi_uses() + int32_indirect_uses(), int32_non_phi_uses() + int32_indirect_uses(),
double_non_phi_uses() + double_indirect_uses(), double_non_phi_uses() + double_indirect_uses(),
tagged_non_phi_uses() + tagged_indirect_uses()); tagged_non_phi_uses() + tagged_indirect_uses());
stream->Add("%s%s]",
is_live() ? "_live" : "",
IsConvertibleToInteger() ? "" : "_ncti");
} }

27
deps/v8/src/hydrogen-instructions.h

@ -513,19 +513,6 @@ class HValue: public ZoneObject {
static const int kChangesToDependsFlagsLeftShift = 1; 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) { static int ConvertChangesToDependsFlags(int flags) {
return flags << kChangesToDependsFlagsLeftShift; return flags << kChangesToDependsFlagsLeftShift;
} }
@ -629,6 +616,8 @@ class HValue: public ZoneObject {
void ClearAllSideEffects() { flags_ &= ~AllSideEffects(); } void ClearAllSideEffects() { flags_ &= ~AllSideEffects(); }
bool HasSideEffects() const { return (flags_ & AllSideEffects()) != 0; } bool HasSideEffects() const { return (flags_ & AllSideEffects()) != 0; }
int ChangesFlags() const { return flags_ & ChangesFlagsMask(); }
Range* range() const { return range_; } Range* range() const { return range_; }
bool HasRange() const { return range_ != NULL; } bool HasRange() const { return range_ != NULL; }
void AddNewRange(Range* r); void AddNewRange(Range* r);
@ -693,6 +682,15 @@ class HValue: public ZoneObject {
} }
private: 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. // A flag mask to mark an instruction as having arbitrary side effects.
static int AllSideEffects() { static int AllSideEffects() {
return ChangesFlagsMask() & ~(1 << kChangesOsrEntries); return ChangesFlagsMask() & ~(1 << kChangesOsrEntries);
@ -1696,7 +1694,10 @@ class HJSArrayLength: public HTemplateInstruction<2> {
return Representation::Tagged(); return Representation::Tagged();
} }
virtual void PrintDataTo(StringStream* stream);
HValue* value() { return OperandAt(0); } HValue* value() { return OperandAt(0); }
HValue* typecheck() { return OperandAt(1); }
DECLARE_CONCRETE_INSTRUCTION(JSArrayLength) DECLARE_CONCRETE_INSTRUCTION(JSArrayLength)

450
deps/v8/src/hydrogen.cc

@ -1382,7 +1382,7 @@ void HGlobalValueNumberer::ComputeBlockSideEffects() {
int id = block->block_id(); int id = block->block_id();
int side_effects = 0; int side_effects = 0;
while (instr != NULL) { while (instr != NULL) {
side_effects |= (instr->flags() & HValue::ChangesFlagsMask()); side_effects |= instr->ChangesFlags();
instr = instr->next(); instr = instr->next();
} }
block_side_effects_[id] |= side_effects; block_side_effects_[id] |= side_effects;
@ -1499,7 +1499,7 @@ void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) {
HInstruction* instr = block->first(); HInstruction* instr = block->first();
while (instr != NULL) { while (instr != NULL) {
HInstruction* next = instr->next(); HInstruction* next = instr->next();
int flags = (instr->flags() & HValue::ChangesFlagsMask()); int flags = instr->ChangesFlags();
if (flags != 0) { if (flags != 0) {
ASSERT(!instr->CheckFlag(HValue::kUseGVN)); ASSERT(!instr->CheckFlag(HValue::kUseGVN));
// Clear all instructions in the map that are affected by side effects. // Clear all instructions in the map that are affected by side effects.
@ -2273,10 +2273,6 @@ HGraph* HGraphBuilder::CreateGraph() {
return NULL; return NULL;
} }
SetupScope(scope); 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 // 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 // environment will be used by the Lithium translation as the initial
@ -2298,6 +2294,19 @@ HGraph* HGraphBuilder::CreateGraph() {
current_block()->Goto(body_entry); current_block()->Goto(body_entry);
body_entry->SetJoinId(AstNode::kFunctionEntryId); body_entry->SetJoinId(AstNode::kFunctionEntryId);
set_current_block(body_entry); 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()); VisitStatements(info()->function()->body());
if (HasStackOverflow()) return NULL; if (HasStackOverflow()) return NULL;
@ -3119,54 +3128,63 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
Variable* variable = expr->AsVariable(); Variable* variable = expr->var();
if (variable == NULL) { if (variable->mode() == Variable::LET) {
return Bailout("reference to rewritten variable"); return Bailout("reference to let variable");
} else if (variable->IsStackAllocated()) { }
HValue* value = environment()->Lookup(variable); switch (variable->location()) {
if (variable->mode() == Variable::CONST && case Variable::UNALLOCATED: {
value == graph()->GetConstantHole()) { LookupResult lookup;
return Bailout("reference to uninitialized const variable"); GlobalPropertyAccess type =
} LookupGlobalProperty(variable, &lookup, false);
return ast_context()->ReturnValue(value);
} else if (variable->IsContextSlot()) { if (type == kUseCell &&
if (variable->mode() == Variable::CONST) { info()->global_object()->IsAccessCheckNeeded()) {
return Bailout("reference to const context slot"); type = kUseGeneric;
} }
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);
if (type == kUseCell && if (type == kUseCell) {
info()->global_object()->IsAccessCheckNeeded()) { Handle<GlobalObject> global(info()->global_object());
type = kUseGeneric; 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) { case Variable::PARAMETER:
Handle<GlobalObject> global(info()->global_object()); case Variable::LOCAL: {
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); HValue* value = environment()->Lookup(variable);
bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); if (variable->mode() == Variable::CONST &&
HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); value == graph()->GetConstantHole()) {
return ast_context()->ReturnInstruction(instr, expr->id()); return Bailout("reference to uninitialized const variable");
} else { }
HValue* context = environment()->LookupContext(); return ast_context()->ReturnValue(value);
HGlobalObject* global_object = new(zone()) HGlobalObject(context); }
AddInstruction(global_object);
HLoadGlobalGeneric* instr = case Variable::CONTEXT: {
new(zone()) HLoadGlobalGeneric(context, if (variable->mode() == Variable::CONST) {
global_object, return Bailout("reference to const context slot");
variable->name(), }
ast_context()->is_for_typeof()); HValue* context = BuildContextChainWalk(variable);
instr->set_position(expr->position()); HLoadContextSlot* instr =
ASSERT(instr->HasSideEffects()); new(zone()) HLoadContextSlot(context, variable->index());
return ast_context()->ReturnInstruction(instr, expr->id()); 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");
} }
} }
@ -3578,51 +3596,61 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var,
void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
Expression* target = expr->target(); Expression* target = expr->target();
VariableProxy* proxy = target->AsVariableProxy(); VariableProxy* proxy = target->AsVariableProxy();
Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty(); 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 // We have a second position recorded in the FullCodeGenerator to have
// type feedback for the binary operation. // type feedback for the binary operation.
BinaryOperation* operation = expr->binary_operation(); BinaryOperation* operation = expr->binary_operation();
if (var != NULL) { if (proxy != NULL) {
if (var->mode() == Variable::CONST) { Variable* var = proxy->var();
return Bailout("unsupported const compound assignment"); if (var->mode() == Variable::CONST || var->mode() == Variable::LET) {
return Bailout("unsupported let or const compound assignment");
} }
CHECK_ALIVE(VisitForValue(operation)); CHECK_ALIVE(VisitForValue(operation));
if (var->is_global()) { switch (var->location()) {
HandleGlobalVariableAssignment(var, case Variable::UNALLOCATED:
Top(), HandleGlobalVariableAssignment(var,
expr->position(), Top(),
expr->AssignmentId()); expr->position(),
} else if (var->IsStackAllocated()) { expr->AssignmentId());
Bind(var, Top()); break;
} else if (var->IsContextSlot()) {
// Bail out if we try to mutate a parameter value in a function using case Variable::PARAMETER:
// the arguments object. We do not (yet) correctly handle the case Variable::LOCAL:
// arguments property of the function. Bind(var, Top());
if (info()->scope()->arguments() != NULL) { break;
// Parameters will rewrite to context slots. We have no direct way
// to detect that the variable is a parameter. case Variable::CONTEXT: {
int count = info()->scope()->num_parameters(); // Bail out if we try to mutate a parameter value in a function
for (int i = 0; i < count; ++i) { // using the arguments object. We do not (yet) correctly handle the
if (var == info()->scope()->parameter(i)) { // arguments property of the function.
Bailout("assignment to parameter, function uses arguments object"); 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); case Variable::LOOKUP:
int index = var->AsSlot()->index(); return Bailout("compound assignment to lookup slot");
HStoreContextSlot* instr =
new(zone()) HStoreContextSlot(context, index, Top());
AddInstruction(instr);
if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
} else {
return Bailout("compound assignment to lookup slot");
} }
return ast_context()->ReturnValue(Pop()); return ast_context()->ReturnValue(Pop());
@ -3710,16 +3738,18 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
VariableProxy* proxy = expr->target()->AsVariableProxy(); VariableProxy* proxy = expr->target()->AsVariableProxy();
Variable* var = proxy->AsVariable();
Property* prop = expr->target()->AsProperty(); Property* prop = expr->target()->AsProperty();
ASSERT(var == NULL || prop == NULL); ASSERT(proxy == NULL || prop == NULL);
if (expr->is_compound()) { if (expr->is_compound()) {
HandleCompoundAssignment(expr); HandleCompoundAssignment(expr);
return; return;
} }
if (var != NULL) { if (prop != NULL) {
HandlePropertyAssignment(expr);
} else if (proxy != NULL) {
Variable* var = proxy->var();
if (var->mode() == Variable::CONST) { if (var->mode() == Variable::CONST) {
if (expr->op() != Token::INIT_CONST) { if (expr->op() != Token::INIT_CONST) {
return Bailout("non-initializer assignment to const"); return Bailout("non-initializer assignment to const");
@ -3731,59 +3761,61 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
// variables (e.g. initialization inside a loop). // variables (e.g. initialization inside a loop).
HValue* old_value = environment()->Lookup(var); HValue* old_value = environment()->Lookup(var);
AddInstruction(new HUseConst(old_value)); AddInstruction(new HUseConst(old_value));
} else if (var->mode() == Variable::LET) {
return Bailout("unsupported assignment to let");
} }
if (proxy->IsArguments()) return Bailout("assignment to arguments"); if (proxy->IsArguments()) return Bailout("assignment to arguments");
// Handle the assignment. // Handle the assignment.
if (var->IsStackAllocated()) { switch (var->location()) {
// We do not allow the arguments object to occur in a context where it case Variable::UNALLOCATED:
// may escape, but assignments to stack-allocated locals are CHECK_ALIVE(VisitForValue(expr->value()));
// permitted. HandleGlobalVariableAssignment(var,
CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); Top(),
HValue* value = Pop(); expr->position(),
Bind(var, value); expr->AssignmentId());
return ast_context()->ReturnValue(value); return ast_context()->ReturnValue(Pop());
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);
}
} else if (var->IsContextSlot()) { case Variable::CONTEXT: {
ASSERT(var->mode() != Variable::CONST); ASSERT(var->mode() != Variable::CONST);
// Bail out if we try to mutate a parameter value in a function using // Bail out if we try to mutate a parameter value in a function using
// the arguments object. We do not (yet) correctly handle the // the arguments object. We do not (yet) correctly handle the
// arguments property of the function. // arguments property of the function.
if (info()->scope()->arguments() != NULL) { if (info()->scope()->arguments() != NULL) {
// Parameters will rewrite to context slots. We have no direct way // Parameters will rewrite to context slots. We have no direct way
// to detect that the variable is a parameter. // to detect that the variable is a parameter.
int count = info()->scope()->num_parameters(); int count = info()->scope()->num_parameters();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
if (var == info()->scope()->parameter(i)) { if (var == info()->scope()->parameter(i)) {
Bailout("assignment to parameter, function uses arguments object"); return Bailout("assignment to parameter in arguments object");
}
} }
} }
}
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());
} else if (var->is_global()) { CHECK_ALIVE(VisitForValue(expr->value()));
CHECK_ALIVE(VisitForValue(expr->value())); HValue* context = BuildContextChainWalk(var);
HandleGlobalVariableAssignment(var, HStoreContextSlot* instr =
Top(), new(zone()) HStoreContextSlot(context, var->index(), Top());
expr->position(), AddInstruction(instr);
expr->AssignmentId()); if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
return ast_context()->ReturnValue(Pop()); return ast_context()->ReturnValue(Pop());
}
} else { case Variable::LOOKUP:
return Bailout("assignment to LOOKUP or const CONTEXT variable"); return Bailout("assignment to LOOKUP variable");
} }
} else if (prop != NULL) {
HandlePropertyAssignment(expr);
} else { } else {
return Bailout("invalid left-hand side in assignment"); return Bailout("invalid left-hand side in assignment");
} }
@ -4795,13 +4827,15 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
// Found pattern f.apply(receiver, arguments). // Found pattern f.apply(receiver, arguments).
VisitForValue(prop->obj()); VisitForValue(prop->obj());
if (HasStackOverflow() || current_block() == NULL) return true; if (HasStackOverflow() || current_block() == NULL) return true;
HValue* function = Pop(); HValue* function = Top();
AddCheckConstantFunction(expr, function, function_map, true);
Drop(1);
VisitForValue(args->at(0)); VisitForValue(args->at(0));
if (HasStackOverflow() || current_block() == NULL) return true; if (HasStackOverflow() || current_block() == NULL) return true;
HValue* receiver = Pop(); HValue* receiver = Pop();
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
AddCheckConstantFunction(expr, function, function_map, true);
HInstruction* result = HInstruction* result =
new(zone()) HApplyArguments(function, receiver, length, elements); new(zone()) HApplyArguments(function, receiver, length, elements);
result->set_position(expr->position()); result->set_position(expr->position());
@ -4893,10 +4927,12 @@ void HGraphBuilder::VisitCall(Call* expr) {
} }
} else { } else {
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); VariableProxy* proxy = expr->expression()->AsVariableProxy();
bool global_call = (var != NULL) && var->is_global() && !var->is_this(); // FIXME.
bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
if (global_call) { if (global_call) {
Variable* var = proxy->var();
bool known_global_function = false; bool known_global_function = false;
// If there is a global property cell for the name at compile time and // 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 // access check is not enabled we assume that the function will not change
@ -5060,20 +5096,8 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
void HGraphBuilder::VisitDelete(UnaryOperation* expr) { void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
Property* prop = expr->expression()->AsProperty(); Property* prop = expr->expression()->AsProperty();
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (prop == NULL && var == NULL) { if (prop != 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) {
CHECK_ALIVE(VisitForValue(prop->obj())); CHECK_ALIVE(VisitForValue(prop->obj()));
CHECK_ALIVE(VisitForValue(prop->key())); CHECK_ALIVE(VisitForValue(prop->key()));
HValue* key = Pop(); HValue* key = Pop();
@ -5081,10 +5105,26 @@ void HGraphBuilder::VisitDelete(UnaryOperation* expr) {
HValue* context = environment()->LookupContext(); HValue* context = environment()->LookupContext();
HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key); HDeleteProperty* instr = new(zone()) HDeleteProperty(context, obj, key);
return ast_context()->ReturnInstruction(instr, expr->id()); return ast_context()->ReturnInstruction(instr, expr->id());
} else if (var->is_global()) { } else if (proxy != NULL) {
Bailout("delete with global variable"); 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 { } 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());
} }
} }
@ -5231,9 +5271,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
Expression* target = expr->expression(); Expression* target = expr->expression();
VariableProxy* proxy = target->AsVariableProxy(); VariableProxy* proxy = target->AsVariableProxy();
Variable* var = proxy->AsVariable();
Property* prop = target->AsProperty(); Property* prop = target->AsProperty();
if (var == NULL && prop == NULL) { if (proxy == NULL && prop == NULL) {
return Bailout("invalid lhs in count operation"); return Bailout("invalid lhs in count operation");
} }
@ -5245,7 +5284,8 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
HValue* input = NULL; // ToNumber(original_input). HValue* input = NULL; // ToNumber(original_input).
HValue* after = NULL; // The result after incrementing or decrementing. HValue* after = NULL; // The result after incrementing or decrementing.
if (var != NULL) { if (proxy != NULL) {
Variable* var = proxy->var();
if (var->mode() == Variable::CONST) { if (var->mode() == Variable::CONST) {
return Bailout("unsupported count operation with const"); return Bailout("unsupported count operation with const");
} }
@ -5257,36 +5297,45 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
input = returns_original_input ? Top() : Pop(); input = returns_original_input ? Top() : Pop();
Push(after); Push(after);
if (var->is_global()) { switch (var->location()) {
HandleGlobalVariableAssignment(var, case Variable::UNALLOCATED:
after, HandleGlobalVariableAssignment(var,
expr->position(), after,
expr->AssignmentId()); expr->position(),
} else if (var->IsStackAllocated()) { expr->AssignmentId());
Bind(var, after); break;
} else if (var->IsContextSlot()) {
// Bail out if we try to mutate a parameter value in a function using case Variable::PARAMETER:
// the arguments object. We do not (yet) correctly handle the case Variable::LOCAL:
// arguments property of the function. Bind(var, after);
if (info()->scope()->arguments() != NULL) { break;
// Parameters will rewrite to context slots. We have no direct way
// to detect that the variable is a parameter. case Variable::CONTEXT: {
int count = info()->scope()->num_parameters(); // Bail out if we try to mutate a parameter value in a function
for (int i = 0; i < count; ++i) { // using the arguments object. We do not (yet) correctly handle the
if (var == info()->scope()->parameter(i)) { // arguments property of the function.
Bailout("assignment to parameter, function uses arguments object"); 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); case Variable::LOOKUP:
int index = var->AsSlot()->index(); return Bailout("lookup variable in count operation");
HStoreContextSlot* instr =
new(zone()) HStoreContextSlot(context, index, after);
AddInstruction(instr);
if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
} else {
return Bailout("lookup variable in count operation");
} }
} else { } else {
@ -5698,12 +5747,12 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
// residing in new space. If it is we assume that the function will stay the // residing in new space. If it is we assume that the function will stay the
// same. // same.
Handle<JSFunction> target = Handle<JSFunction>::null(); Handle<JSFunction> target = Handle<JSFunction>::null();
Variable* var = expr->right()->AsVariableProxy()->AsVariable(); VariableProxy* proxy = expr->right()->AsVariableProxy();
bool global_function = (var != NULL) && var->is_global() && !var->is_this(); bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
if (global_function && if (global_function &&
info()->has_global_object() && info()->has_global_object() &&
!info()->global_object()->IsAccessCheckNeeded()) { !info()->global_object()->IsAccessCheckNeeded()) {
Handle<String> name = var->name(); Handle<String> name = proxy->name();
Handle<GlobalObject> global(info()->global_object()); Handle<GlobalObject> global(info()->global_object());
LookupResult lookup; LookupResult lookup;
global->Lookup(*name, &lookup); global->Lookup(*name, &lookup);
@ -5802,15 +5851,42 @@ void HGraphBuilder::VisitThisFunction(ThisFunction* expr) {
void HGraphBuilder::VisitDeclaration(Declaration* decl) { void HGraphBuilder::VisitDeclaration(Declaration* decl) {
// We support only declarations that do not require code generation. HandleDeclaration(decl->proxy(), decl->mode(), decl->fun());
Variable* var = decl->proxy()->var(); }
if (!var->IsStackAllocated() || decl->fun() != NULL) {
return Bailout("unsupported declaration");
} void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
Variable::Mode mode,
if (decl->mode() == Variable::CONST) { FunctionLiteral* function) {
ASSERT(var->IsStackAllocated()); if (mode == Variable::LET) return Bailout("unsupported let declaration");
environment()->Bind(var, graph()->GetConstantHole()); 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");
} }
} }

12
deps/v8/src/hydrogen.h

@ -455,12 +455,11 @@ class HEnvironment: public ZoneObject {
// by 1 (receiver is parameter index -1 but environment index 0). // by 1 (receiver is parameter index -1 but environment index 0).
// Stack-allocated local indices are shifted by the number of parameters. // Stack-allocated local indices are shifted by the number of parameters.
int IndexFor(Variable* variable) const { int IndexFor(Variable* variable) const {
Slot* slot = variable->AsSlot(); ASSERT(variable->IsStackAllocated());
ASSERT(slot != NULL && slot->IsStackAllocated()); int shift = variable->IsParameter()
int shift = (slot->type() == Slot::PARAMETER)
? 1 ? 1
: parameter_count_ + specials_count_; : parameter_count_ + specials_count_;
return slot->index() + shift; return variable->index() + shift;
} }
Handle<JSFunction> closure_; Handle<JSFunction> closure_;
@ -779,6 +778,10 @@ class HGraphBuilder: public AstVisitor {
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
#undef INLINE_FUNCTION_GENERATOR_DECLARATION #undef INLINE_FUNCTION_GENERATOR_DECLARATION
void HandleDeclaration(VariableProxy* proxy,
Variable::Mode mode,
FunctionLiteral* function);
void VisitDelete(UnaryOperation* expr); void VisitDelete(UnaryOperation* expr);
void VisitVoid(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr);
void VisitTypeof(UnaryOperation* expr); void VisitTypeof(UnaryOperation* expr);
@ -851,7 +854,6 @@ class HGraphBuilder: public AstVisitor {
TypeInfo info, TypeInfo info,
HValue* value, HValue* value,
Representation rep); Representation rep);
void AssumeRepresentation(HValue* value, Representation rep);
static Representation ToRepresentation(TypeInfo info); static Representation ToRepresentation(TypeInfo info);
void SetupScope(Scope* scope); void SetupScope(Scope* scope);

14
deps/v8/src/ia32/builtins-ia32.cc

@ -373,7 +373,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
__ LeaveConstructFrame(); __ LeaveConstructFrame();
// Remove caller arguments from the stack and return. // Remove caller arguments from the stack and return.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ pop(ecx); __ pop(ecx);
__ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
__ push(ecx); __ push(ecx);
@ -923,7 +923,7 @@ static void AllocateEmptyJSArray(MacroAssembler* masm,
// Fill the FixedArray with the hole value. Inline the code if short. // Fill the FixedArray with the hole value. Inline the code if short.
// Reconsider loop unfolding if kPreallocatedArrayElements gets changed. // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
static const int kLoopUnfoldLimit = 4; static const int kLoopUnfoldLimit = 4;
ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit); STATIC_ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
if (initial_capacity <= kLoopUnfoldLimit) { if (initial_capacity <= kLoopUnfoldLimit) {
// Use a scratch register here to have only one reloc info when unfolding // Use a scratch register here to have only one reloc info when unfolding
// the loop. // the loop.
@ -975,7 +975,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// Allocate the JSArray object together with space for a FixedArray with the // Allocate the JSArray object together with space for a FixedArray with the
// requested elements. // requested elements.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
times_half_pointer_size, // array_size is a smi. times_half_pointer_size, // array_size is a smi.
array_size, array_size,
@ -1100,7 +1100,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ bind(&argc_one_or_more); __ bind(&argc_one_or_more);
__ cmp(eax, 1); __ cmp(eax, 1);
__ j(not_equal, &argc_two_or_more); __ j(not_equal, &argc_two_or_more);
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize)); __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
__ test(ecx, Operand(ecx)); __ test(ecx, Operand(ecx));
__ j(not_zero, &not_empty_array); __ j(not_zero, &not_empty_array);
@ -1155,7 +1155,7 @@ static void ArrayNativeCode(MacroAssembler* masm,
// Handle construction of an array from a list of arguments. // Handle construction of an array from a list of arguments.
__ bind(&argc_two_or_more); __ bind(&argc_two_or_more);
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ SmiTag(eax); // Convet argc to a smi. __ SmiTag(eax); // Convet argc to a smi.
// eax: array_size (smi) // eax: array_size (smi)
// edi: constructor // edi: constructor
@ -1437,7 +1437,7 @@ static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
// Preserve the number of arguments on the stack. Must preserve eax, // Preserve the number of arguments on the stack. Must preserve eax,
// ebx and ecx because these registers are used when copying the // ebx and ecx because these registers are used when copying the
// arguments and the receiver. // arguments and the receiver.
ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kSmiTagSize == 1);
__ lea(edi, Operand(eax, eax, times_1, kSmiTag)); __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
__ push(edi); __ push(edi);
} }
@ -1451,7 +1451,7 @@ static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
__ leave(); __ leave();
// Remove caller arguments from the stack. // Remove caller arguments from the stack.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ pop(ecx); __ pop(ecx);
__ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
__ push(ecx); __ push(ecx);

109
deps/v8/src/ia32/code-stubs-ia32.cc

@ -3396,8 +3396,8 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// a sequential string or an external string. // a sequential string or an external string.
// In the case of a sliced string its offset has to be taken into account. // In the case of a sliced string its offset has to be taken into account.
Label cons_string, check_encoding; Label cons_string, check_encoding;
STATIC_ASSERT((kConsStringTag < kExternalStringTag)); STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
__ cmp(Operand(ebx), Immediate(kExternalStringTag)); __ cmp(Operand(ebx), Immediate(kExternalStringTag));
__ j(less, &cons_string); __ j(less, &cons_string);
__ j(equal, &runtime); __ j(equal, &runtime);
@ -4872,8 +4872,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Handle non-flat strings. // Handle non-flat strings.
__ and_(result_, kStringRepresentationMask); __ and_(result_, kStringRepresentationMask);
STATIC_ASSERT((kConsStringTag < kExternalStringTag)); STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
__ cmp(result_, kExternalStringTag); __ cmp(result_, kExternalStringTag);
__ j(greater, &sliced_string, Label::kNear); __ j(greater, &sliced_string, Label::kNear);
__ j(equal, &call_runtime_); __ j(equal, &call_runtime_);
@ -4907,7 +4907,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Check for 1-byte or 2-byte string. // Check for 1-byte or 2-byte string.
__ bind(&flat_string); __ bind(&flat_string);
STATIC_ASSERT(kAsciiStringTag != 0); STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ test(result_, Immediate(kStringEncodingMask)); __ test(result_, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear); __ j(not_zero, &ascii_string, Label::kNear);
@ -5178,8 +5179,9 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
__ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset));
__ and_(ecx, Operand(edi)); __ and_(ecx, Operand(edi));
STATIC_ASSERT(kStringEncodingMask == kAsciiStringTag); STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
__ test(ecx, Immediate(kAsciiStringTag)); STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ test(ecx, Immediate(kStringEncodingMask));
__ j(zero, &non_ascii); __ j(zero, &non_ascii);
__ bind(&ascii_data); __ bind(&ascii_data);
// Allocate an acsii cons string. // Allocate an acsii cons string.
@ -5210,7 +5212,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
__ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag);
__ j(equal, &ascii_data); __ j(equal, &ascii_data);
// Allocate a two byte cons string. // Allocate a two byte cons string.
__ AllocateConsString(ecx, edi, no_reg, &string_add_runtime); __ AllocateTwoByteConsString(ecx, edi, no_reg, &string_add_runtime);
__ jmp(&allocated); __ jmp(&allocated);
// Handle creating a flat result. First check that both strings are not // Handle creating a flat result. First check that both strings are not
@ -5236,12 +5238,13 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// ebx: length of resulting flat string as a smi // ebx: length of resulting flat string as a smi
// edx: second string // edx: second string
Label non_ascii_string_add_flat_result; 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)); __ 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); __ j(zero, &non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); __ 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); __ j(zero, &string_add_runtime);
// Both strings are ascii strings. As they are short they are both flat. // Both strings are ascii strings. As they are short they are both flat.
@ -5281,7 +5284,7 @@ void StringAddStub::Generate(MacroAssembler* masm) {
// edx: second string // edx: second string
__ bind(&non_ascii_string_add_flat_result); __ bind(&non_ascii_string_add_flat_result);
__ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); __ 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); __ j(not_zero, &string_add_runtime);
// Both strings are two byte strings. As they are short they are both // Both strings are two byte strings. As they are short they are both
// flat. // flat.
@ -5642,9 +5645,6 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
void SubStringStub::Generate(MacroAssembler* masm) { void SubStringStub::Generate(MacroAssembler* masm) {
Label runtime; Label runtime;
if (FLAG_string_slices) {
__ jmp(&runtime);
}
// Stack frame on entry. // Stack frame on entry.
// esp[0]: return address // esp[0]: return address
// esp[4]: to // esp[4]: to
@ -5706,7 +5706,84 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
__ Set(ecx, Immediate(2)); __ Set(ecx, Immediate(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(&copy_routine);
__ bind(&result_longer_than_two);
// eax: string
// ebx: instance type
// ecx: sub string length
// edx: from index (smi)
Label allocate_slice, sliced_string, seq_string;
__ cmp(ecx, SlicedString::kMinLength);
// Short slice. Copy instead of slicing.
__ j(less, &copy_routine);
STATIC_ASSERT(kSeqStringTag == 0);
__ test(ebx, Immediate(kStringRepresentationMask));
__ j(zero, &seq_string, Label::kNear);
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
STATIC_ASSERT(kIsIndirectStringMask != 0);
__ test(ebx, Immediate(kIsIndirectStringMask));
// External string. Jump to runtime.
__ j(zero, &runtime);
Factory* factory = masm->isolate()->factory();
__ test(ebx, Immediate(kSlicedNotConsMask));
__ j(not_zero, &sliced_string, Label::kNear);
// Cons string. Check whether it is flat, then fetch first part.
__ cmp(FieldOperand(eax, ConsString::kSecondOffset),
factory->empty_string());
__ j(not_equal, &runtime);
__ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
__ jmp(&allocate_slice, Label::kNear);
__ bind(&sliced_string);
// Sliced string. Fetch parent and correct start index by offset.
__ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
__ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
__ jmp(&allocate_slice, Label::kNear);
__ bind(&seq_string);
// Sequential string. Just move string to the right register.
__ mov(edi, eax);
__ 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);
__ 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);
__ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
__ bind(&set_slice_header);
__ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
__ SmiTag(ecx);
__ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
__ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
__ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
Immediate(String::kEmptyHashField));
__ jmp(&return_eax);
__ bind(&copy_routine);
} else {
__ bind(&result_longer_than_two);
}
// eax: string // eax: string
// ebx: instance type // ebx: instance type
// ecx: result string length // ecx: result string length

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

@ -41,7 +41,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#define __ ACCESS_MASM(masm_) #define __ ACCESS_MASM(masm_)
@ -192,14 +191,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy parameters into context if necessary. // Copy parameters into context if necessary.
int num_parameters = info->scope()->num_parameters(); int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Variable* var = scope()->parameter(i);
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize; (num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack. // Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset)); __ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context. // 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); __ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved // Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid // registers, so we have use a third register to avoid
@ -241,7 +240,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
ArgumentsAccessStub stub(type); ArgumentsAccessStub stub(type);
__ CallStub(&stub); __ CallStub(&stub);
Move(arguments->AsSlot(), eax, ebx, edx); SetVar(arguments, eax, ebx, edx);
} }
if (FLAG_trace) { if (FLAG_trace) {
@ -255,17 +254,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
scope()->VisitIllegalRedeclaration(this); scope()->VisitIllegalRedeclaration(this);
} else { } else {
PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a // For named function expressions, declare the function name as a
// constant. // constant.
if (scope()->is_function_scope() && scope()->function() != NULL) { 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()); VisitDeclarations(scope()->declarations());
} }
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok; Label ok;
ExternalReference stack_limit = ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(isolate()); ExternalReference::address_of_stack_limit(isolate());
@ -371,27 +372,29 @@ void FullCodeGenerator::verify_stack_height() {
} }
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 { void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); ASSERT(var->IsStackAllocated() || var->IsContextSlot());
__ mov(result_register(), slot_operand); codegen()->GetVar(result_register(), var);
} }
void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); ASSERT(var->IsStackAllocated() || var->IsContextSlot());
MemOperand operand = codegen()->VarOperand(var, result_register());
// Memory operands can be pushed directly. // Memory operands can be pushed directly.
__ push(slot_operand); __ push(operand);
codegen()->increment_stack_height(); 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. // 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()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->DoTest(this); codegen()->DoTest(this);
} }
@ -615,44 +618,54 @@ void FullCodeGenerator::Split(Condition cc,
} }
MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { MemOperand FullCodeGenerator::StackOperand(Variable* var) {
switch (slot->type()) { ASSERT(var->IsStackAllocated());
case Slot::PARAMETER: // Offset is negative because higher indexes are at lower addresses.
case Slot::LOCAL: int offset = -var->index() * kPointerSize;
return Operand(ebp, SlotOffset(slot)); // Adjust by a (parameter or local) base offset.
case Slot::CONTEXT: { if (var->IsParameter()) {
int context_chain_length = offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
scope()->ContextChainLength(slot->var()->scope()); } else {
__ LoadContext(scratch, context_chain_length); offset += JavaScriptFrameConstants::kLocal0Offset;
return ContextOperand(scratch, slot->index());
}
case Slot::LOOKUP:
UNREACHABLE();
} }
UNREACHABLE(); return Operand(ebp, offset);
return Operand(eax, 0);
} }
void FullCodeGenerator::Move(Register destination, Slot* source) { MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
MemOperand location = EmitSlotSearch(source, destination); ASSERT(var->IsContextSlot() || var->IsStackAllocated());
__ mov(destination, location); 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, void FullCodeGenerator::GetVar(Register dest, Variable* var) {
Register src, ASSERT(var->IsContextSlot() || var->IsStackAllocated());
Register scratch1, MemOperand location = VarOperand(var, dest);
Register scratch2) { __ mov(dest, location);
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);
__ mov(location, src); __ mov(location, src);
// Emit the write barrier code if the location is in the heap. // Emit the write barrier code if the location is in the heap.
if (dst->type() == Slot::CONTEXT) { if (var->IsContextSlot()) {
int offset = Context::SlotOffset(dst->index()); int offset = Context::SlotOffset(var->index());
ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi)); ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
__ RecordWrite(scratch1, offset, src, scratch2); __ RecordWrite(scratch0, offset, src, scratch1);
} }
} }
@ -683,29 +696,33 @@ void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
} }
void FullCodeGenerator::EmitDeclaration(Variable* variable, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function) { FunctionLiteral* function,
Comment cmnt(masm_, "[ Declaration"); int* global_count) {
ASSERT(variable != NULL); // Must have been resolved. // If it was not possible to allocate the variable at compile time, we
Slot* slot = variable->AsSlot(); // need to "declare" it at runtime to make sure it actually exists in the
ASSERT(slot != NULL); // local context.
switch (slot->type()) { Variable* variable = proxy->var();
case Slot::PARAMETER: switch (variable->location()) {
case Slot::LOCAL: case Variable::UNALLOCATED:
if (mode == Variable::CONST) { ++(*global_count);
__ mov(Operand(ebp, SlotOffset(slot)), break;
Immediate(isolate()->factory()->the_hole_value()));
} else if (function != NULL) { case Variable::PARAMETER:
case Variable::LOCAL:
if (function != NULL) {
Comment cmnt(masm_, "[ Declaration");
VisitForAccumulatorValue(function); VisitForAccumulatorValue(function);
__ mov(Operand(ebp, SlotOffset(slot)), result_register()); __ mov(StackOperand(variable), result_register());
} else if (mode == Variable::CONST || mode == Variable::LET) {
Comment cmnt(masm_, "[ Declaration");
__ mov(StackOperand(variable),
Immediate(isolate()->factory()->the_hole_value()));
} }
break; break;
case Slot::CONTEXT: case Variable::CONTEXT:
// We bypass the general EmitSlotSearch because we know more about
// this specific context.
// The variable in the decl always resides in the current function // The variable in the decl always resides in the current function
// context. // context.
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
@ -717,23 +734,28 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ cmp(ebx, isolate()->factory()->catch_context_map()); __ cmp(ebx, isolate()->factory()->catch_context_map());
__ Check(not_equal, "Declaration in catch context."); __ Check(not_equal, "Declaration in catch context.");
} }
if (mode == Variable::CONST) { if (function != NULL) {
__ mov(ContextOperand(esi, slot->index()), Comment cmnt(masm_, "[ Declaration");
Immediate(isolate()->factory()->the_hole_value()));
// No write barrier since the hole value is in old space.
} else if (function != NULL) {
VisitForAccumulatorValue(function); VisitForAccumulatorValue(function);
__ mov(ContextOperand(esi, slot->index()), result_register()); __ mov(ContextOperand(esi, variable->index()), result_register());
int offset = Context::SlotOffset(slot->index()); int offset = Context::SlotOffset(variable->index());
__ mov(ebx, esi); __ mov(ebx, esi);
__ RecordWrite(ebx, offset, result_register(), ecx); __ RecordWrite(ebx, offset, result_register(), ecx);
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
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; break;
case Slot::LOOKUP: { case Variable::LOOKUP: {
Comment cmnt(masm_, "[ Declaration");
__ push(esi); __ push(esi);
__ push(Immediate(variable->name())); __ 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 || ASSERT(mode == Variable::VAR ||
mode == Variable::CONST || mode == Variable::CONST ||
mode == Variable::LET); mode == Variable::LET);
@ -744,13 +766,13 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// 'undefined') because we may have a (legal) redeclaration and we // 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value. // must not destroy the current value.
increment_stack_height(3); increment_stack_height(3);
if (mode == Variable::CONST) { if (function != NULL) {
VisitForStackValue(function);
} else if (mode == Variable::CONST || mode == Variable::LET) {
__ push(Immediate(isolate()->factory()->the_hole_value())); __ push(Immediate(isolate()->factory()->the_hole_value()));
increment_stack_height(); increment_stack_height();
} else if (function != NULL) {
VisitForStackValue(function);
} else { } else {
__ push(Immediate(Smi::FromInt(0))); // No initial value! __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
increment_stack_height(); increment_stack_height();
} }
__ CallRuntime(Runtime::kDeclareContextSlot, 4); __ CallRuntime(Runtime::kDeclareContextSlot, 4);
@ -761,18 +783,15 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
} }
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
}
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals. // Call the runtime to declare the globals.
__ push(esi); // The context is the first argument. __ push(esi); // The context is the first argument.
__ push(Immediate(pairs)); __ push(Immediate(pairs));
__ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags())));
__ push(Immediate(Smi::FromInt(strict_mode_flag()))); __ CallRuntime(Runtime::kDeclareGlobals, 3);
__ CallRuntime(Runtime::kDeclareGlobals, 4);
// Return value is ignored. // Return value is ignored.
} }
@ -1071,10 +1090,9 @@ void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
} }
void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
Slot* slot, TypeofState typeof_state,
TypeofState typeof_state, Label* slow) {
Label* slow) {
Register context = esi; Register context = esi;
Register temp = edx; Register temp = edx;
@ -1123,7 +1141,7 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
// All extension objects were empty and it is safe to use a global // All extension objects were empty and it is safe to use a global
// load IC call. // load IC call.
__ mov(eax, GlobalObjectOperand()); __ mov(eax, GlobalObjectOperand());
__ mov(ecx, slot->var()->name()); __ mov(ecx, var->name());
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
? RelocInfo::CODE_TARGET ? RelocInfo::CODE_TARGET
@ -1132,14 +1150,13 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
} }
MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
Slot* slot, Label* slow) {
Label* slow) { ASSERT(var->IsContextSlot());
ASSERT(slot->type() == Slot::CONTEXT);
Register context = esi; Register context = esi;
Register temp = ebx; 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->num_heap_slots() > 0) {
if (s->calls_eval()) { if (s->calls_eval()) {
// Check that extension is NULL. // Check that extension is NULL.
@ -1159,60 +1176,31 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
// This function is used only for loads, not stores, so it's safe to // 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 // return an esi-based operand (the write barrier cannot be allowed to
// destroy the esi register). // destroy the esi register).
return ContextOperand(context, slot->index()); return ContextOperand(context, var->index());
} }
void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
Slot* slot, TypeofState typeof_state,
TypeofState typeof_state, Label* slow,
Label* slow, Label* done) {
Label* done) {
// Generate fast-case code for variables that might be shadowed by // Generate fast-case code for variables that might be shadowed by
// eval-introduced variables. Eval is used a lot without // eval-introduced variables. Eval is used a lot without
// introducing variables. In those cases, we do not want to // introducing variables. In those cases, we do not want to
// perform a runtime call for all variables in the scope // perform a runtime call for all variables in the scope
// containing the eval. // containing the eval.
if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { if (var->mode() == Variable::DYNAMIC_GLOBAL) {
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
__ jmp(done); __ jmp(done);
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { } else if (var->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); Variable* local = var->local_if_not_shadowed();
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
if (potential_slot != NULL) { if (local->mode() == Variable::CONST) {
// Generate fast case for locals that rewrite to slots. __ cmp(eax, isolate()->factory()->the_hole_value());
__ mov(eax, __ j(not_equal, done);
ContextSlotOperandCheckExtensions(potential_slot, slow)); __ mov(eax, isolate()->factory()->undefined_value());
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);
}
}
} }
__ jmp(done);
} }
} }
@ -1222,54 +1210,60 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
SetSourcePosition(proxy->position()); SetSourcePosition(proxy->position());
Variable* var = proxy->var(); Variable* var = proxy->var();
// Three cases: non-this global variables, lookup slots, and all other // Three cases: global variables, lookup variables, and all other types of
// types of slots. // variables.
Slot* slot = var->AsSlot(); switch (var->location()) {
ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); case Variable::UNALLOCATED: {
Comment cmnt(masm_, "Global variable");
if (slot == NULL) { // Use inline caching. Variable name is passed in ecx and the global
Comment cmnt(masm_, "Global variable"); // object in eax.
// Use inline caching. Variable name is passed in ecx and the global __ mov(eax, GlobalObjectOperand());
// object on the stack. __ mov(ecx, var->name());
__ mov(eax, GlobalObjectOperand()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
__ mov(ecx, var->name()); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); context()->Plug(eax);
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT); break;
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); 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;
}
} else { case Variable::LOOKUP: {
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) Label done, slow;
? "Context slot" // Generate code for loading from variables potentially shadowed
: "Stack slot"); // by eval-introduced variables.
if (var->mode() == Variable::CONST) { EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
// Constants may be the hole value if they have not been initialized. __ bind(&slow);
// Unhole them. Comment cmnt(masm_, "Lookup variable");
Label done; __ push(esi); // Context.
MemOperand slot_operand = EmitSlotSearch(slot, eax); __ push(Immediate(var->name()));
__ mov(eax, slot_operand); __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ cmp(eax, isolate()->factory()->the_hole_value());
__ j(not_equal, &done, Label::kNear);
__ mov(eax, isolate()->factory()->undefined_value());
__ bind(&done); __ bind(&done);
context()->Plug(eax); context()->Plug(eax);
} else { break;
context()->Plug(slot);
} }
} }
} }
@ -1812,14 +1806,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var, void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) { Token::Value op) {
ASSERT(var != NULL); if (var->IsUnallocated()) {
ASSERT(var->is_global() || var->AsSlot() != NULL); // Global var, const, or let.
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.
__ mov(ecx, var->name()); __ mov(ecx, var->name());
__ mov(edx, GlobalObjectOperand()); __ mov(edx, GlobalObjectOperand());
Handle<Code> ic = is_strict_mode() Handle<Code> ic = is_strict_mode()
@ -1828,66 +1816,79 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
} else if (op == Token::INIT_CONST) { } else if (op == Token::INIT_CONST) {
// Like var declarations, const declarations are hoisted to function // Const initializers need a write barrier.
// scope. However, unlike var initializers, const initializers are able ASSERT(!var->IsParameter()); // No const parameters.
// to drill a hole to that function context, even from inside a 'with' if (var->IsStackLocal()) {
// context. We thus bypass the normal static scope lookup. Label skip;
Slot* slot = var->AsSlot(); __ mov(edx, StackOperand(var));
Label skip; __ cmp(edx, isolate()->factory()->the_hole_value());
switch (slot->type()) { __ j(not_equal, &skip);
case Slot::PARAMETER: __ mov(StackOperand(var), eax);
// No const parameters. __ bind(&skip);
UNREACHABLE(); } else {
break; ASSERT(var->IsContextSlot() || var->IsLookupSlot());
case Slot::LOCAL: // Like var declarations, const declarations are hoisted to function
__ mov(edx, Operand(ebp, SlotOffset(slot))); // scope. However, unlike var initializers, const initializers are
__ cmp(edx, isolate()->factory()->the_hole_value()); // able to drill a hole to that function context, even from inside a
__ j(not_equal, &skip); // 'with' context. We thus bypass the normal static scope lookup for
__ mov(Operand(ebp, SlotOffset(slot)), eax); // var->IsContextSlot().
break; __ push(eax);
case Slot::CONTEXT: __ push(esi);
case Slot::LOOKUP: __ push(Immediate(var->name()));
__ push(eax); __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
__ push(esi);
__ push(Immediate(var->name()));
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
break;
} }
__ bind(&skip);
} else if (var->mode() != Variable::CONST) { } else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
// Perform the assignment for non-const variables. Const assignments // Non-initializing assignment to let variable needs a write barrier.
// are simply skipped. if (var->IsLookupSlot()) {
Slot* slot = var->AsSlot(); __ push(eax); // Value.
switch (slot->type()) { __ push(esi); // Context.
case Slot::PARAMETER: __ push(Immediate(var->name()));
case Slot::LOCAL: __ push(Immediate(Smi::FromInt(strict_mode_flag())));
// Perform the assignment. __ CallRuntime(Runtime::kStoreContextSlot, 4);
__ mov(Operand(ebp, SlotOffset(slot)), eax); } else {
break; ASSERT(var->IsStackAllocated() || var->IsContextSlot());
Label assign;
case Slot::CONTEXT: { MemOperand location = VarOperand(var, ecx);
MemOperand target = EmitSlotSearch(slot, ecx); __ mov(edx, location);
// Perform the assignment and issue the write barrier. __ cmp(edx, isolate()->factory()->the_hole_value());
__ mov(target, eax); __ j(not_equal, &assign, Label::kNear);
// The value of the assignment is in eax. RecordWrite clobbers its __ push(Immediate(var->name()));
// register arguments. __ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&assign);
__ mov(location, eax);
if (var->IsContextSlot()) {
__ mov(edx, eax); __ mov(edx, eax);
int offset = Context::SlotOffset(slot->index()); __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx);
__ RecordWrite(ecx, offset, edx, ebx);
break;
} }
}
case Slot::LOOKUP: } else if (var->mode() != Variable::CONST) {
// Call the runtime for the assignment. // Assignment to var or initializing assignment to let.
__ push(eax); // Value. if (var->IsStackAllocated() || var->IsContextSlot()) {
__ push(esi); // Context. MemOperand location = VarOperand(var, ecx);
__ push(Immediate(var->name())); if (FLAG_debug_code && op == Token::INIT_LET) {
__ push(Immediate(Smi::FromInt(strict_mode_flag()))); // Check for an uninitialized let binding.
__ CallRuntime(Runtime::kStoreContextSlot, 4); __ mov(edx, location);
break; __ cmp(edx, isolate()->factory()->the_hole_value());
__ Check(equal, "Let binding re-initialization.");
}
// 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.
} }
@ -2094,8 +2095,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
// Push the receiver of the enclosing function. // Push the receiver of the enclosing function.
__ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize)); __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
// Push the strict mode flag. // Push the strict mode flag. In harmony mode every eval call
__ push(Immediate(Smi::FromInt(strict_mode_flag()))); // 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 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
? Runtime::kResolvePossiblyDirectEvalNoLookup ? Runtime::kResolvePossiblyDirectEvalNoLookup
@ -2111,18 +2117,18 @@ void FullCodeGenerator::VisitCall(Call* expr) {
#endif #endif
Comment cmnt(masm_, "[ Call"); Comment cmnt(masm_, "[ Call");
Expression* fun = expr->expression(); Expression* callee = expr->expression();
Variable* var = fun->AsVariableProxy()->AsVariable(); 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 // In a call to eval, we first call %ResolvePossiblyDirectEval to
// resolve the function we need to call and the receiver of the // resolve the function we need to call and the receiver of the call.
// call. Then we call the resolved function using the given // Then we call the resolved function using the given arguments.
// arguments.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length(); int arg_count = args->length();
{ PreservePositionScope pos_scope(masm()->positions_recorder()); { PreservePositionScope pos_scope(masm()->positions_recorder());
VisitForStackValue(fun); VisitForStackValue(callee);
// Reserved receiver slot. // Reserved receiver slot.
__ push(Immediate(isolate()->factory()->undefined_value())); __ push(Immediate(isolate()->factory()->undefined_value()));
increment_stack_height(); increment_stack_height();
@ -2132,15 +2138,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
} }
// If we know that eval can only be shadowed by eval-introduced // If we know that eval can only be shadowed by eval-introduced
// variables we attempt to load the global eval function directly // variables we attempt to load the global eval function directly in
// in generated code. If we succeed, there is no need to perform a // generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system. // context lookup in the runtime system.
Label done; 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; Label slow;
EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
NOT_INSIDE_TYPEOF,
&slow);
// Push the function and resolve eval. // Push the function and resolve eval.
__ push(eax); __ push(eax);
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
@ -2148,13 +2153,11 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ bind(&slow); __ 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. // resolve eval.
__ push(Operand(esp, (arg_count + 1) * kPointerSize)); __ push(Operand(esp, (arg_count + 1) * kPointerSize));
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); 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 // The runtime call returns a pair of values in eax (function) and
// edx (receiver). Touch up the stack with the right values. // edx (receiver). Touch up the stack with the right values.
@ -2171,75 +2174,67 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
decrement_stack_height(arg_count + 1); // Function is left on the stack. decrement_stack_height(arg_count + 1); // Function is left on the stack.
context()->DropAndPlug(1, eax); 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 global object as receiver for the call IC.
__ push(GlobalObjectOperand()); __ push(GlobalObjectOperand());
increment_stack_height(); increment_stack_height();
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (var != NULL && var->AsSlot() != NULL &&
var->AsSlot()->type() == Slot::LOOKUP) { } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
// Call to a lookup slot (dynamically introduced variable). // Call to a lookup slot (dynamically introduced variable).
Label slow, done; Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder()); { PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed // Generate code for loading from variables potentially shadowed by
// by eval-introduced variables. // eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(), EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
NOT_INSIDE_TYPEOF,
&slow,
&done);
} }
__ bind(&slow); __ bind(&slow);
// Call the runtime to find the function to call (returned in eax) // Call the runtime to find the function to call (returned in eax) and
// and the object holding it (returned in edx). // the object holding it (returned in edx).
__ push(context_register()); __ push(context_register());
__ push(Immediate(var->name())); __ push(Immediate(proxy->name()));
__ CallRuntime(Runtime::kLoadContextSlot, 2); __ CallRuntime(Runtime::kLoadContextSlot, 2);
__ push(eax); // Function. __ push(eax); // Function.
increment_stack_height();
__ push(edx); // Receiver. __ push(edx); // Receiver.
increment_stack_height(); increment_stack_height(2);
// If fast case code has been generated, emit code to push the // If fast case code has been generated, emit code to push the function
// function and receiver and have the slow path jump around this // and receiver and have the slow path jump around this code.
// code.
if (done.is_linked()) { if (done.is_linked()) {
Label call; Label call;
__ jmp(&call); __ jmp(&call, Label::kNear);
__ bind(&done); __ bind(&done);
// Push function. Stack height already incremented in slow case above. // Push function. Stack height already incremented in slow case
// above.
__ push(eax); __ push(eax);
// The receiver is implicitly the global receiver. Indicate this // The receiver is implicitly the global receiver. Indicate this by
// by passing the hole to the call function stub. // passing the hole to the call function stub.
__ push(Immediate(isolate()->factory()->the_hole_value())); __ push(Immediate(isolate()->factory()->the_hole_value()));
__ bind(&call); __ bind(&call);
} }
// The receiver is either the global receiver or an object found // The receiver is either the global receiver or an object found by
// by LoadContextSlot. That object could be the hole if the // LoadContextSlot. That object could be the hole if the receiver is
// receiver is implicitly the global object. // implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
} else if (fun->AsProperty() != NULL) {
// Call to an object property. } else if (property != NULL) {
Property* prop = fun->AsProperty(); { PreservePositionScope scope(masm()->positions_recorder());
Literal* key = prop->key()->AsLiteral(); VisitForStackValue(property->obj());
if (key != NULL && key->handle()->IsSymbol()) { }
// Call to a named property, use call IC. if (property->key()->IsPropertyName()) {
{ PreservePositionScope scope(masm()->positions_recorder()); EmitCallWithIC(expr,
VisitForStackValue(prop->obj()); property->key()->AsLiteral()->handle(),
} RelocInfo::CODE_TARGET);
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else { } else {
// Call to a keyed property. EmitKeyedCallWithIC(expr, property->key());
{ PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
EmitKeyedCallWithIC(expr, prop->key());
} }
} else { } else {
// Call to an arbitrary expression not handled specially above.
{ PreservePositionScope scope(masm()->positions_recorder()); { PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(fun); VisitForStackValue(callee);
} }
// Load global receiver object. // Load global receiver object.
__ mov(ebx, GlobalObjectOperand()); __ mov(ebx, GlobalObjectOperand());
@ -3199,7 +3194,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
Label done, not_found; Label done, not_found;
// tmp now holds finger offset as a smi. // tmp now holds finger offset as a smi.
ASSERT(kSmiTag == 0 && kSmiTagSize == 1); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
__ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp)); __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
__ j(not_equal, &not_found); __ j(not_equal, &not_found);
@ -3611,31 +3606,32 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) { switch (expr->op()) {
case Token::DELETE: { case Token::DELETE: {
Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
Property* prop = expr->expression()->AsProperty(); Property* property = expr->expression()->AsProperty();
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (prop != NULL) { if (property != NULL) {
VisitForStackValue(prop->obj()); VisitForStackValue(property->obj());
VisitForStackValue(prop->key()); VisitForStackValue(property->key());
__ push(Immediate(Smi::FromInt(strict_mode_flag()))); __ push(Immediate(Smi::FromInt(strict_mode_flag())));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
decrement_stack_height(2); decrement_stack_height(2);
context()->Plug(eax); 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 // 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()); ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
if (var->is_global()) { if (var->IsUnallocated()) {
__ push(GlobalObjectOperand()); __ push(GlobalObjectOperand());
__ push(Immediate(var->name())); __ push(Immediate(var->name()));
__ push(Immediate(Smi::FromInt(kNonStrictMode))); __ push(Immediate(Smi::FromInt(kNonStrictMode)));
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(eax); context()->Plug(eax);
} else if (var->AsSlot() != NULL && } else if (var->IsStackAllocated() || var->IsContextSlot()) {
var->AsSlot()->type() != Slot::LOOKUP) { // Result of deleting non-global variables is false. 'this' is
// Result of deleting non-global, non-dynamic variables is false. // not really a variable, though we implement it as one. The
// The subexpression does not have side effects. // subexpression does not have side effects.
context()->Plug(false); context()->Plug(var->is_this());
} else { } else {
// Non-global variable. Call the runtime to try to delete from the // Non-global variable. Call the runtime to try to delete from the
// context where the variable was introduced. // context where the variable was introduced.
@ -3932,7 +3928,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
ASSERT(!context()->IsEffect()); ASSERT(!context()->IsEffect());
ASSERT(!context()->IsTest()); 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"); Comment cmnt(masm_, "Global variable");
__ mov(eax, GlobalObjectOperand()); __ mov(eax, GlobalObjectOperand());
__ mov(ecx, Immediate(proxy->name())); __ mov(ecx, Immediate(proxy->name()));
@ -3942,15 +3938,12 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
__ call(ic); __ call(ic);
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
context()->Plug(eax); context()->Plug(eax);
} else if (proxy != NULL && } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
proxy->var()->AsSlot() != NULL &&
proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
Label done, slow; Label done, slow;
// Generate code for loading from variables potentially shadowed // Generate code for loading from variables potentially shadowed
// by eval-introduced variables. // by eval-introduced variables.
Slot* slot = proxy->var()->AsSlot(); EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
__ bind(&slow); __ bind(&slow);
__ push(esi); __ push(esi);
@ -4242,8 +4235,8 @@ void FullCodeGenerator::EnterFinallyBlock() {
ASSERT(!result_register().is(edx)); ASSERT(!result_register().is(edx));
__ pop(edx); __ pop(edx);
__ sub(Operand(edx), Immediate(masm_->CodeObject())); __ sub(Operand(edx), Immediate(masm_->CodeObject()));
ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(kSmiTag == 0);
__ SmiTag(edx); __ SmiTag(edx);
__ push(edx); __ push(edx);
// Store result register while executing finally block. // Store result register while executing finally block.
@ -4262,6 +4255,34 @@ void FullCodeGenerator::ExitFinallyBlock() {
} }
#undef __
#define __ ACCESS_MASM(masm())
FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
int* stack_depth,
int* context_length) {
// The macros used here must preserve the result register.
// Because the handler block contains the context of the finally
// code, we can restore it directly from there for the finally code
// rather than iteratively unwinding contexts via their previous
// links.
__ Drop(*stack_depth); // Down to the handler block.
if (*context_length > 0) {
// Restore the context to its dedicated register and the stack.
__ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
}
__ PopTryHandler();
__ call(finally_entry_);
*stack_depth = 0;
*context_length = 0;
return previous_;
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

4
deps/v8/src/ia32/ic-ia32.cc

@ -324,7 +324,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
__ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
__ j(above_equal, out_of_range); __ j(above_equal, out_of_range);
// Fast case: Do the load. // Fast case: Do the load.
ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
__ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
__ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value())); __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value()));
// In case the loaded value is the_hole we have to consult GetProperty // In case the loaded value is the_hole we have to consult GetProperty
@ -358,7 +358,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
__ j(zero, index_string); __ j(zero, index_string);
// Is the string a symbol? // Is the string a symbol?
ASSERT(kSymbolTag != 0); STATIC_ASSERT(kSymbolTag != 0);
__ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
__ j(zero, not_symbol); __ j(zero, not_symbol);
} }

12
deps/v8/src/ia32/lithium-codegen-ia32.cc

@ -194,14 +194,14 @@ bool LCodeGen::GeneratePrologue() {
// Copy parameters into context if necessary. // Copy parameters into context if necessary.
int num_parameters = scope()->num_parameters(); int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Variable* var = scope()->parameter(i);
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (var->IsContextSlot()) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize; (num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack. // Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset)); __ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context. // 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); __ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved // Update the write barrier. This clobbers all involved
// registers, so we have to use a third register to avoid // registers, so we have to use a third register to avoid
@ -3175,7 +3175,6 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
void LCodeGen::DoStoreKeyedFastDoubleElement( void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) { LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value()); XMMRegister value = ToDoubleRegister(instr->value());
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
Label have_value; Label have_value;
__ ucomisd(value, value); __ ucomisd(value, value);
@ -3234,8 +3233,6 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the indirect string shape: slice or cons. // Dispatch on the indirect string shape: slice or cons.
Label cons_string; Label cons_string;
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
ASSERT(IsPowerOf2(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
__ test(result, Immediate(kSlicedNotConsMask)); __ test(result, Immediate(kSlicedNotConsMask));
__ j(zero, &cons_string, Label::kNear); __ j(zero, &cons_string, Label::kNear);
@ -3271,7 +3268,8 @@ void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
// Dispatch on the encoding: ASCII or two-byte. // Dispatch on the encoding: ASCII or two-byte.
Label ascii_string; Label ascii_string;
STATIC_ASSERT(kAsciiStringTag != 0); STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ test(result, Immediate(kStringEncodingMask)); __ test(result, Immediate(kStringEncodingMask));
__ j(not_zero, &ascii_string, Label::kNear); __ j(not_zero, &ascii_string, Label::kNear);

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

@ -148,7 +148,7 @@ void MacroAssembler::RecordWrite(Register object,
Label done; Label done;
// Skip barrier if writing a smi. // Skip barrier if writing a smi.
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(kSmiTag == 0);
JumpIfSmi(value, &done, Label::kNear); JumpIfSmi(value, &done, Label::kNear);
InNewSpace(object, value, equal, &done, Label::kNear); InNewSpace(object, value, equal, &done, Label::kNear);
@ -166,8 +166,8 @@ void MacroAssembler::RecordWrite(Register object,
// Array access: calculate the destination address in the same manner as // Array access: calculate the destination address in the same manner as
// KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
// into an array of words. // into an array of words.
ASSERT_EQ(1, kSmiTagSize); STATIC_ASSERT(kSmiTagSize == 1);
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(kSmiTag == 0);
lea(dst, Operand(object, dst, times_half_pointer_size, lea(dst, Operand(object, dst, times_half_pointer_size,
FixedArray::kHeaderSize - kHeapObjectTag)); FixedArray::kHeaderSize - kHeapObjectTag));
} }
@ -193,7 +193,7 @@ void MacroAssembler::RecordWrite(Register object,
Label done; Label done;
// Skip barrier if writing a smi. // Skip barrier if writing a smi.
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(kSmiTag == 0);
JumpIfSmi(value, &done, Label::kNear); JumpIfSmi(value, &done, Label::kNear);
InNewSpace(object, value, equal, &done); InNewSpace(object, value, equal, &done);
@ -326,7 +326,7 @@ Condition MacroAssembler::IsObjectStringType(Register heap_object,
Register instance_type) { Register instance_type) {
mov(map, FieldOperand(heap_object, HeapObject::kMapOffset)); mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset)); movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0); STATIC_ASSERT(kNotStringTag != 0);
test(instance_type, Immediate(kIsNotStringMask)); test(instance_type, Immediate(kIsNotStringMask));
return zero; return zero;
} }
@ -1172,7 +1172,7 @@ void MacroAssembler::AllocateAsciiString(Register result,
} }
void MacroAssembler::AllocateConsString(Register result, void MacroAssembler::AllocateTwoByteConsString(Register result,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Label* gc_required) { Label* gc_required) {
@ -1208,6 +1208,42 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
} }
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.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(isolate()->factory()->sliced_string_map()));
}
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.
mov(FieldOperand(result, HeapObject::kMapOffset),
Immediate(isolate()->factory()->sliced_ascii_string_map()));
}
// Copy memory, byte-by-byte, from source to destination. Not optimized for // Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. The contents of scratch and length are destroyed. // long or aligned copies. The contents of scratch and length are destroyed.
// Source and destination are incremented by length. // Source and destination are incremented by length.
@ -2166,7 +2202,7 @@ void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register object1,
Register scratch2, Register scratch2,
Label* failure) { Label* failure) {
// Check that both objects are not smis. // Check that both objects are not smis.
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(kSmiTag == 0);
mov(scratch1, Operand(object1)); mov(scratch1, Operand(object1));
and_(scratch1, Operand(object2)); and_(scratch1, Operand(object2));
JumpIfSmi(scratch1, failure); JumpIfSmi(scratch1, failure);

21
deps/v8/src/ia32/macro-assembler-ia32.h

@ -275,8 +275,8 @@ class MacroAssembler: public Assembler {
// Smi tagging support. // Smi tagging support.
void SmiTag(Register reg) { void SmiTag(Register reg) {
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kSmiTagSize == 1);
add(reg, Operand(reg)); add(reg, Operand(reg));
} }
void SmiUntag(Register reg) { void SmiUntag(Register reg) {
@ -285,9 +285,9 @@ class MacroAssembler: public Assembler {
// Modifies the register even if it does not contain a Smi! // Modifies the register even if it does not contain a Smi!
void SmiUntag(Register reg, Label* is_smi) { void SmiUntag(Register reg, Label* is_smi) {
ASSERT(kSmiTagSize == 1); STATIC_ASSERT(kSmiTagSize == 1);
sar(reg, kSmiTagSize); sar(reg, kSmiTagSize);
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
j(not_carry, is_smi); j(not_carry, is_smi);
} }
@ -437,7 +437,7 @@ class MacroAssembler: public Assembler {
// Allocate a raw cons string object. Only the map field of the result is // Allocate a raw cons string object. Only the map field of the result is
// initialized. // initialized.
void AllocateConsString(Register result, void AllocateTwoByteConsString(Register result,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Label* gc_required); Label* gc_required);
@ -446,6 +446,17 @@ class MacroAssembler: public Assembler {
Register scratch2, Register scratch2,
Label* gc_required); 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);
// Copy memory, byte-by-byte, from source to destination. Not optimized for // Copy memory, byte-by-byte, from source to destination. Not optimized for
// long or aligned copies. // long or aligned copies.
// The contents of index and scratch are destroyed. // The contents of index and scratch are destroyed.

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

@ -1080,7 +1080,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
MaybeObject* result = Execution::HandleStackGuardInterrupt(); MaybeObject* result = Execution::HandleStackGuardInterrupt();
if (*code_handle != re_code) { // Return address no longer valid if (*code_handle != re_code) { // Return address no longer valid
int delta = *code_handle - re_code; int delta = code_handle->address() - re_code->address();
// Overwrite the return address on the stack. // Overwrite the return address on the stack.
*return_address += delta; *return_address += delta;
} }

2
deps/v8/src/ia32/stub-cache-ia32.cc

@ -273,7 +273,7 @@ static void GenerateStringCheck(MacroAssembler* masm,
// Check that the object is a string. // Check that the object is a string.
__ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0); STATIC_ASSERT(kNotStringTag != 0);
__ test(scratch, Immediate(kNotStringTag)); __ test(scratch, Immediate(kNotStringTag));
__ j(not_zero, non_string_object); __ j(not_zero, non_string_object);
} }

5
deps/v8/src/isolate.cc

@ -1409,7 +1409,6 @@ Isolate::Isolate()
global_handles_(NULL), global_handles_(NULL),
context_switcher_(NULL), context_switcher_(NULL),
thread_manager_(NULL), thread_manager_(NULL),
ast_sentinels_(NULL),
string_tracker_(NULL), string_tracker_(NULL),
regexp_stack_(NULL), regexp_stack_(NULL),
embedder_data_(NULL) { embedder_data_(NULL) {
@ -1546,9 +1545,6 @@ Isolate::~Isolate() {
delete regexp_stack_; delete regexp_stack_;
regexp_stack_ = NULL; regexp_stack_ = NULL;
delete ast_sentinels_;
ast_sentinels_ = NULL;
delete descriptor_lookup_cache_; delete descriptor_lookup_cache_;
descriptor_lookup_cache_ = NULL; descriptor_lookup_cache_ = NULL;
delete context_slot_cache_; delete context_slot_cache_;
@ -1710,7 +1706,6 @@ bool Isolate::Init(Deserializer* des) {
bootstrapper_ = new Bootstrapper(); bootstrapper_ = new Bootstrapper();
handle_scope_implementer_ = new HandleScopeImplementer(this); handle_scope_implementer_ = new HandleScopeImplementer(this);
stub_cache_ = new StubCache(this); stub_cache_ = new StubCache(this);
ast_sentinels_ = new AstSentinels();
regexp_stack_ = new RegExpStack(); regexp_stack_ = new RegExpStack();
regexp_stack_->isolate_ = this; regexp_stack_->isolate_ = this;

4
deps/v8/src/isolate.h

@ -47,7 +47,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class AstSentinels;
class Bootstrapper; class Bootstrapper;
class CodeGenerator; class CodeGenerator;
class CodeRange; class CodeRange;
@ -878,8 +877,6 @@ class Isolate {
return &objects_string_input_buffer_; return &objects_string_input_buffer_;
} }
AstSentinels* ast_sentinels() { return ast_sentinels_; }
RuntimeState* runtime_state() { return &runtime_state_; } RuntimeState* runtime_state() { return &runtime_state_; }
StaticResource<SafeStringInputBuffer>* compiler_safe_string_input_buffer() { StaticResource<SafeStringInputBuffer>* compiler_safe_string_input_buffer() {
@ -1138,7 +1135,6 @@ class Isolate {
GlobalHandles* global_handles_; GlobalHandles* global_handles_;
ContextSwitcher* context_switcher_; ContextSwitcher* context_switcher_;
ThreadManager* thread_manager_; ThreadManager* thread_manager_;
AstSentinels* ast_sentinels_;
RuntimeState runtime_state_; RuntimeState runtime_state_;
StaticResource<SafeStringInputBuffer> compiler_safe_string_input_buffer_; StaticResource<SafeStringInputBuffer> compiler_safe_string_input_buffer_;
Builtins builtins_; Builtins builtins_;

5
deps/v8/src/json.js

@ -337,11 +337,12 @@ function JSONStringify(value, replacer, space) {
return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
} }
function SetupJSON() { function SetUpJSON() {
%CheckIsBootstrapping();
InstallFunctions($JSON, DONT_ENUM, $Array( InstallFunctions($JSON, DONT_ENUM, $Array(
"parse", JSONParse, "parse", JSONParse,
"stringify", JSONStringify "stringify", JSONStringify
)); ));
} }
SetupJSON(); SetUpJSON()

8
deps/v8/src/jsregexp.cc

@ -2661,7 +2661,8 @@ int TextNode::GreedyLoopTextLength() {
// this alternative and back to this choice node. If there are variable // this alternative and back to this choice node. If there are variable
// length nodes or other complications in the way then return a sentinel // length nodes or other complications in the way then return a sentinel
// value indicating that a greedy loop cannot be constructed. // value indicating that a greedy loop cannot be constructed.
int ChoiceNode::GreedyLoopTextLength(GuardedAlternative* alternative) { int ChoiceNode::GreedyLoopTextLengthForAlternative(
GuardedAlternative* alternative) {
int length = 0; int length = 0;
RegExpNode* node = alternative->node(); RegExpNode* node = alternative->node();
// Later we will generate code for all these text nodes using recursion // Later we will generate code for all these text nodes using recursion
@ -2700,7 +2701,8 @@ void LoopChoiceNode::AddContinueAlternative(GuardedAlternative alt) {
void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
RegExpMacroAssembler* macro_assembler = compiler->macro_assembler(); RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
if (trace->stop_node() == this) { if (trace->stop_node() == this) {
int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); int text_length =
GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
ASSERT(text_length != kNodeIsTooComplexForGreedyLoops); ASSERT(text_length != kNodeIsTooComplexForGreedyLoops);
// Update the counter-based backtracking info on the stack. This is an // Update the counter-based backtracking info on the stack. This is an
// optimization for greedy loops (see below). // optimization for greedy loops (see below).
@ -2893,7 +2895,7 @@ void ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
Trace* current_trace = trace; Trace* current_trace = trace;
int text_length = GreedyLoopTextLength(&(alternatives_->at(0))); int text_length = GreedyLoopTextLengthForAlternative(&(alternatives_->at(0)));
bool greedy_loop = false; bool greedy_loop = false;
Label greedy_loop_label; Label greedy_loop_label;
Trace counter_backtrack_trace; Trace counter_backtrack_trace;

2
deps/v8/src/jsregexp.h

@ -1071,7 +1071,7 @@ class ChoiceNode: public RegExpNode {
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; } virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
protected: protected:
int GreedyLoopTextLength(GuardedAlternative* alternative); int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
ZoneList<GuardedAlternative>* alternatives_; ZoneList<GuardedAlternative>* alternatives_;
private: private:

7
deps/v8/src/liveedit.cc

@ -860,8 +860,7 @@ class FunctionInfoListener {
int j = 0; int j = 0;
for (int i = 0; i < list.length(); i++) { for (int i = 0; i < list.length(); i++) {
Variable* var1 = list[i]; Variable* var1 = list[i];
Slot* slot = var1->AsSlot(); if (var1->IsContextSlot()) {
if (slot != NULL && slot->type() == Slot::CONTEXT) {
if (j != i) { if (j != i) {
list[j] = var1; list[j] = var1;
} }
@ -873,7 +872,7 @@ class FunctionInfoListener {
for (int k = 1; k < j; k++) { for (int k = 1; k < j; k++) {
int l = k; int l = k;
for (int m = k + 1; m < j; m++) { 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; l = m;
} }
} }
@ -887,7 +886,7 @@ class FunctionInfoListener {
SetElementNonStrict( SetElementNonStrict(
scope_info_list, scope_info_list,
scope_info_length, scope_info_length,
Handle<Smi>(Smi::FromInt(list[i]->AsSlot()->index()))); Handle<Smi>(Smi::FromInt(list[i]->index())));
scope_info_length++; scope_info_length++;
} }
SetElementNonStrict(scope_info_list, SetElementNonStrict(scope_info_list,

18
deps/v8/src/macros.py

@ -122,7 +122,7 @@ macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once. # 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_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(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_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0)); macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
@ -170,7 +170,7 @@ macro CAPTURE(index) = (3 + (index));
const CAPTURE0 = 3; const CAPTURE0 = 3;
const CAPTURE1 = 4; const CAPTURE1 = 4;
# PropertyDescriptor return value indices - must match # PropertyDescriptor return value indices - must match
# PropertyDescriptorIndices in runtime.cc. # PropertyDescriptorIndices in runtime.cc.
const IS_ACCESSOR_INDEX = 0; const IS_ACCESSOR_INDEX = 0;
const VALUE_INDEX = 1; const VALUE_INDEX = 1;
@ -179,3 +179,17 @@ const SETTER_INDEX = 3;
const WRITABLE_INDEX = 4; const WRITABLE_INDEX = 4;
const ENUMERABLE_INDEX = 5; const ENUMERABLE_INDEX = 5;
const CONFIGURABLE_INDEX = 6; 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;

14
deps/v8/src/math.js

@ -38,7 +38,7 @@ const $abs = MathAbs;
function MathConstructor() {} function MathConstructor() {}
%FunctionSetInstanceClassName(MathConstructor, 'Math'); %FunctionSetInstanceClassName(MathConstructor, 'Math');
const $Math = new MathConstructor(); const $Math = new MathConstructor();
$Math.__proto__ = global.Object.prototype; $Math.__proto__ = $Object.prototype;
%SetProperty(global, "Math", $Math, DONT_ENUM); %SetProperty(global, "Math", $Math, DONT_ENUM);
// ECMA 262 - 15.8.2.1 // ECMA 262 - 15.8.2.1
@ -195,8 +195,9 @@ function MathTan(x) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupMath() { function SetUpMath() {
// Setup math constants. %CheckIsBootstrapping();
// Set up math constants.
// ECMA-262, section 15.8.1.1. // ECMA-262, section 15.8.1.1.
%OptimizeObjectForAddingMultipleProperties($Math, 8); %OptimizeObjectForAddingMultipleProperties($Math, 8);
%SetProperty($Math, %SetProperty($Math,
@ -236,7 +237,7 @@ function SetupMath() {
DONT_ENUM | DONT_DELETE | READ_ONLY); DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Math); %ToFastProperties($Math);
// Setup non-enumerable functions of the Math object and // Set up non-enumerable functions of the Math object and
// set their names. // set their names.
InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array( InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array(
"random", MathRandom, "random", MathRandom,
@ -258,7 +259,6 @@ function SetupMath() {
"max", MathMax, "max", MathMax,
"min", MathMin "min", MathMin
)); ));
}; }
SetupMath(); SetUpMath();

570
deps/v8/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 // If this object gets passed to an error constructor the error will
// get an accessor for .message that constructs a descriptive error // get an accessor for .message that constructs a descriptive error
// message on access. // message on access.
var kAddMessageAccessorsMarker = { }; const kAddMessageAccessorsMarker = { };
var kMessages = 0; // This will be lazily initialized when first needed (and forcibly
// overwritten even though it's const).
var kReplacementMarkers = [ "%0", "%1", "%2", "%3" ]; const kMessages = 0;
function FormatString(format, message) { function FormatString(format, message) {
var args = %MessageGetArguments(message); var args = %MessageGetArguments(message);
@ -56,14 +43,16 @@ function FormatString(format, message) {
var arg_num = 0; var arg_num = 0;
for (var i = 0; i < format.length; i++) { for (var i = 0; i < format.length; i++) {
var str = format[i]; var str = format[i];
for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) { if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
if (str == kReplacementMarkers[arg_num]) { // 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 { try {
str = ToDetailString(args[arg_num]); str = ToDetailString(args[arg_num]);
} catch (e) { } catch (e) {
str = "#<error>"; str = "#<error>";
} }
break;
} }
} }
result += str; result += str;
@ -102,18 +91,16 @@ function ToStringCheckErrorObject(obj) {
function ToDetailString(obj) { function ToDetailString(obj) {
if (obj != null && IS_OBJECT(obj) && if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
obj.toString === $Object.prototype.toString) {
var constructor = obj.constructor; var constructor = obj.constructor;
if (!constructor) return ToStringCheckErrorObject(obj); if (typeof constructor == "function") {
var constructorName = constructor.name; var constructorName = constructor.name;
if (!constructorName || !IS_STRING(constructorName)) { if (IS_STRING(constructorName) && constructorName !== "") {
return ToStringCheckErrorObject(obj); return "#<" + constructorName + ">";
}
} }
return "#<" + constructorName + ">";
} else {
return ToStringCheckErrorObject(obj);
} }
return ToStringCheckErrorObject(obj);
} }
@ -129,10 +116,11 @@ function MakeGenericError(constructor, type, args) {
/** /**
* Setup the Script function and constructor. * Set up the Script function and constructor.
*/ */
%FunctionSetInstanceClassName(Script, 'Script'); %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) { %SetCode(Script, function(x) {
// Script objects can only be created by the VM. // Script objects can only be created by the VM.
throw new $Error("Not supported"); throw new $Error("Not supported");
@ -142,116 +130,132 @@ function MakeGenericError(constructor, type, args) {
// Helper functions; called from the runtime system. // Helper functions; called from the runtime system.
function FormatMessage(message) { function FormatMessage(message) {
if (kMessages === 0) { if (kMessages === 0) {
kMessages = { var messagesDictionary = [
// Error // Error
cyclic_proto: ["Cyclic __proto__ value"], "cyclic_proto", ["Cyclic __proto__ value"],
code_gen_from_strings: ["Code generation from strings disallowed for this context"], "code_gen_from_strings", ["Code generation from strings disallowed for this context"],
// TypeError // TypeError
unexpected_token: ["Unexpected token ", "%0"], "unexpected_token", ["Unexpected token ", "%0"],
unexpected_token_number: ["Unexpected number"], "unexpected_token_number", ["Unexpected number"],
unexpected_token_string: ["Unexpected string"], "unexpected_token_string", ["Unexpected string"],
unexpected_token_identifier: ["Unexpected identifier"], "unexpected_token_identifier", ["Unexpected identifier"],
unexpected_reserved: ["Unexpected reserved word"], "unexpected_reserved", ["Unexpected reserved word"],
unexpected_strict_reserved: ["Unexpected strict mode reserved word"], "unexpected_strict_reserved", ["Unexpected strict mode reserved word"],
unexpected_eos: ["Unexpected end of input"], "unexpected_eos", ["Unexpected end of input"],
malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"], "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"],
unterminated_regexp: ["Invalid regular expression: missing /"], "unterminated_regexp", ["Invalid regular expression: missing /"],
regexp_flags: ["Cannot supply flags when constructing one RegExp from another"], "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"],
incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"], "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"], "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_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_postfix_op", ["Invalid left-hand side expression in postfix operation"],
invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix 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"], "multiple_defaults_in_switch", ["More than one default clause in switch statement"],
newline_after_throw: ["Illegal newline after throw"], "newline_after_throw", ["Illegal newline after throw"],
redeclaration: ["%0", " '", "%1", "' has already been declared"], "redeclaration", ["%0", " '", "%1", "' has already been declared"],
no_catch_or_finally: ["Missing catch or finally after try"], "no_catch_or_finally", ["Missing catch or finally after try"],
unknown_label: ["Undefined label '", "%0", "'"], "unknown_label", ["Undefined label '", "%0", "'"],
uncaught_exception: ["Uncaught ", "%0"], "uncaught_exception", ["Uncaught ", "%0"],
stack_trace: ["Stack Trace:\n", "%0"], "stack_trace", ["Stack Trace:\n", "%0"],
called_non_callable: ["%0", " is not a function"], "called_non_callable", ["%0", " is not a function"],
undefined_method: ["Object ", "%1", " has no method '", "%0", "'"], "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"],
property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"], "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"],
cannot_convert_to_primitive: ["Cannot convert object to primitive value"], "cannot_convert_to_primitive", ["Cannot convert object to primitive value"],
not_constructor: ["%0", " is not a constructor"], "not_constructor", ["%0", " is not a constructor"],
not_defined: ["%0", " is not defined"], "not_defined", ["%0", " is not defined"],
non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"], "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"],
non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"], "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"],
non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"], "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"],
with_expression: ["%0", " has no properties"], "with_expression", ["%0", " has no properties"],
illegal_invocation: ["Illegal invocation"], "illegal_invocation", ["Illegal invocation"],
no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], "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_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"], "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"], "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_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"], "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"],
null_to_object: ["Cannot convert null to object"], "null_to_object", ["Cannot convert null to object"],
reduce_no_initial: ["Reduce of empty array with no initial value"], "reduce_no_initial", ["Reduce of empty array with no initial value"],
getter_must_be_callable: ["Getter must be a function: ", "%0"], "getter_must_be_callable", ["Getter must be a function: ", "%0"],
setter_must_be_callable: ["Setter 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"], "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"], "proto_object_or_null", ["Object prototype may only be an Object or null"],
property_desc_object: ["Property description must be an object: ", "%0"], "property_desc_object", ["Property description must be an object: ", "%0"],
redefine_disallowed: ["Cannot redefine property: ", "%0"], "redefine_disallowed", ["Cannot redefine property: ", "%0"],
define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."], "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."],
non_extensible_proto: ["%0", " is not extensible"], "non_extensible_proto", ["%0", " is not extensible"],
handler_non_object: ["Proxy.", "%0", " called with non-object as handler"], "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"],
handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%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_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_false", ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined 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_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_non_object_prop_names", ["Trap ", "%1", " returned non-object ", "%0"],
proxy_repeated_prop_name: ["Trap ", "%1", " returned repeated property name ", "%2"], "proxy_repeated_prop_name", ["Trap ", "%1", " returned repeated property name ", "%2"],
invalid_weakmap_key: ["Invalid value used as weak map key"], "invalid_weakmap_key", ["Invalid value used as weak map key"],
// RangeError // RangeError
invalid_array_length: ["Invalid array length"], "invalid_array_length", ["Invalid array length"],
stack_overflow: ["Maximum call stack size exceeded"], "stack_overflow", ["Maximum call stack size exceeded"],
// SyntaxError // SyntaxError
unable_to_parse: ["Parse error"], "unable_to_parse", ["Parse error"],
invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"], "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"],
illegal_break: ["Illegal break statement"], "illegal_break", ["Illegal break statement"],
illegal_continue: ["Illegal continue statement"], "illegal_continue", ["Illegal continue statement"],
illegal_return: ["Illegal return statement"], "illegal_return", ["Illegal return statement"],
error_loading_debugger: ["Error loading debugger"], "error_loading_debugger", ["Error loading debugger"],
no_input_to_regexp: ["No input to ", "%0"], "no_input_to_regexp", ["No input to ", "%0"],
invalid_json: ["String '", "%0", "' is not valid JSON"], "invalid_json", ["String '", "%0", "' is not valid JSON"],
circular_structure: ["Converting circular structure to JSON"], "circular_structure", ["Converting circular structure to JSON"],
obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"], "obj_ctor_property_non_object", ["Object.", "%0", " called on non-object"],
called_on_null_or_undefined: ["%0", " called on null or undefined"], "called_on_null_or_undefined", ["%0", " called on null or undefined"],
array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"], "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"],
object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"], "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"],
illegal_access: ["Illegal access"], "illegal_access", ["Illegal access"],
invalid_preparser_data: ["Invalid preparser data for function ", "%0"], "invalid_preparser_data", ["Invalid preparser data for function ", "%0"],
strict_mode_with: ["Strict mode code may not include a with statement"], "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"], "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_arguments", ["Too many arguments in function call (only 32766 allowed)"],
too_many_parameters: ["Too many parameters in function definition (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)"], "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_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_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_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_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_octal_literal", ["Octal literals are not allowed in strict mode."],
strict_duplicate_property: ["Duplicate data property in object literal 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_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"], "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_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_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_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_reserved_word", ["Use of future reserved word in strict mode"],
strict_delete: ["Delete of an unqualified identifier in strict mode."], "strict_delete", ["Delete of an unqualified identifier in strict mode."],
strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"], "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"],
strict_const: ["Use of const in strict mode."], "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_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_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_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_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."], "strict_caller", ["Illegal access to a strict mode caller function."],
unprotected_let: ["Illegal let declaration in unprotected statement context."], "unprotected_let", ["Illegal let declaration in unprotected statement context."],
}; ];
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 message_type = %MessageGetType(message);
var format = kMessages[message_type]; var format = kMessages[message_type];
@ -317,7 +321,7 @@ function MakeError(type, args) {
* @return {number} 0 if input too small, -1 if input too large, * @return {number} 0 if input too small, -1 if input too large,
else the line number. else the line number.
*/ */
Script.prototype.lineFromPosition = function(position) { function ScriptLineFromPosition(position) {
var lower = 0; var lower = 0;
var upper = this.lineCount() - 1; var upper = this.lineCount() - 1;
var line_ends = this.line_ends; var line_ends = this.line_ends;
@ -356,8 +360,8 @@ Script.prototype.lineFromPosition = function(position) {
* @return {SourceLocation} * @return {SourceLocation}
* If line is negative or not in the source null is returned. * If line is negative or not in the source null is returned.
*/ */
Script.prototype.locationFromPosition = function (position, function ScriptLocationFromPosition(position,
include_resource_offset) { include_resource_offset) {
var line = this.lineFromPosition(position); var line = this.lineFromPosition(position);
if (line == -1) return null; if (line == -1) return null;
@ -365,7 +369,9 @@ Script.prototype.locationFromPosition = function (position,
var line_ends = this.line_ends; var line_ends = this.line_ends;
var start = line == 0 ? 0 : line_ends[line - 1] + 1; var start = line == 0 ? 0 : line_ends[line - 1] + 1;
var end = line_ends[line]; 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; var column = position - start;
// Adjust according to the offset within the resource. // Adjust according to the offset within the resource.
@ -390,11 +396,12 @@ Script.prototype.locationFromPosition = function (position,
* @param {number} opt_line The line within the source. Default value is 0 * @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_column The column in within the line. Default value is 0
* @param {number} opt_offset_position The offset from the begining of the * @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} * @return {SourceLocation}
* If line is negative or not in the source null is returned. * 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 // Default is the first line in the script. Lines in the script is relative
// to the offset within the resource. // to the offset within the resource.
var line = 0; var line = 0;
@ -436,7 +443,7 @@ Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_p
* @return {SourceSlice} The source slice or null of the parameters where * @return {SourceSlice} The source slice or null of the parameters where
* invalid * 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 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 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line
@ -463,7 +470,7 @@ Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
} }
Script.prototype.sourceLine = function (opt_line) { function ScriptSourceLine(opt_line) {
// Default is the first line in the script. Lines in the script are relative // Default is the first line in the script. Lines in the script are relative
// to the offset within the resource. // to the offset within the resource.
var line = 0; var line = 0;
@ -489,7 +496,7 @@ Script.prototype.sourceLine = function (opt_line) {
* @return {number} * @return {number}
* Number of source lines. * Number of source lines.
*/ */
Script.prototype.lineCount = function() { function ScriptLineCount() {
// Return number of source lines. // Return number of source lines.
return this.line_ends.length; return this.line_ends.length;
}; };
@ -505,9 +512,10 @@ Script.prototype.lineCount = function() {
* @return {?string} script name if present, value for //@ sourceURL comment * @return {?string} script name if present, value for //@ sourceURL comment
* otherwise. * otherwise.
*/ */
Script.prototype.nameOrSourceURL = function() { function ScriptNameOrSourceURL() {
if (this.name) if (this.name) {
return this.name; return this.name;
}
// TODO(608): the spaces in a regexp below had to be escaped as \040 // 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 // because this file is being processed by js2c whose handling of spaces
// in regexps is broken. Also, ['"] are excluded from allowed URLs to // in regexps is broken. Also, ['"] are excluded from allowed URLs to
@ -533,6 +541,20 @@ Script.prototype.nameOrSourceURL = function() {
} }
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 * Class for source location. A source location is a position within some
* source with the following properties: * source with the following properties:
@ -563,8 +585,6 @@ function SourceLocation(script, position, line, column, start, end) {
this.end = end; this.end = end;
} }
SourceLocation.prototype.__proto__ = null;
const kLineLengthLimit = 78; const kLineLengthLimit = 78;
/** /**
@ -575,7 +595,7 @@ const kLineLengthLimit = 78;
* @param {number} opt_before The number of characters to prefer before the * @param {number} opt_before The number of characters to prefer before the
* position with a default value of 10 less that the limit * 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. // Find the actual limit to use.
var limit; var limit;
var before; var before;
@ -622,11 +642,20 @@ SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
* @return {String} * @return {String}
* Source text for this location. * Source text for this location.
*/ */
SourceLocation.prototype.sourceText = function () { function SourceLocationSourceText() {
return %_CallFunction(this.script.source, this.start, this.end, StringSubstring); 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 * Class for a source slice. A source slice is a part of a script source with
* the following properties: * the following properties:
@ -653,20 +682,23 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) {
this.to_position = to_position; this.to_position = to_position;
} }
SourceSlice.prototype.__proto__ = null;
/** /**
* Get the source text for a SourceSlice * Get the source text for a SourceSlice
* @return {String} Source text for this slice. The last line will include * @return {String} Source text for this slice. The last line will include
* the line terminating characters (if any) * the line terminating characters (if any)
*/ */
SourceSlice.prototype.sourceText = function () { function SourceSliceSourceText() {
return %_CallFunction(this.script.source, return %_CallFunction(this.script.source,
this.from_position, this.from_position,
this.to_position, this.to_position,
StringSubstring); 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 // Returns the offset of the given position within the containing
// line. // line.
@ -721,13 +753,11 @@ function CallSite(receiver, fun, pos) {
this.pos = pos; this.pos = pos;
} }
CallSite.prototype.__proto__ = null; function CallSiteGetThis() {
CallSite.prototype.getThis = function () {
return this.receiver; return this.receiver;
}; };
CallSite.prototype.getTypeName = function () { function CallSiteGetTypeName() {
var constructor = this.receiver.constructor; var constructor = this.receiver.constructor;
if (!constructor) { if (!constructor) {
return %_CallFunction(this.receiver, ObjectToString); return %_CallFunction(this.receiver, ObjectToString);
@ -739,33 +769,33 @@ CallSite.prototype.getTypeName = function () {
return constructorName; return constructorName;
}; };
CallSite.prototype.isToplevel = function () { function CallSiteIsToplevel() {
if (this.receiver == null) { if (this.receiver == null) {
return true; return true;
} }
return IS_GLOBAL(this.receiver); return IS_GLOBAL(this.receiver);
}; };
CallSite.prototype.isEval = function () { function CallSiteIsEval() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script && script.compilation_type == COMPILATION_TYPE_EVAL; return script && script.compilation_type == COMPILATION_TYPE_EVAL;
}; };
CallSite.prototype.getEvalOrigin = function () { function CallSiteGetEvalOrigin() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return FormatEvalOrigin(script); return FormatEvalOrigin(script);
}; };
CallSite.prototype.getScriptNameOrSourceURL = function () { function CallSiteGetScriptNameOrSourceURL() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script ? script.nameOrSourceURL() : null; return script ? script.nameOrSourceURL() : null;
}; };
CallSite.prototype.getFunction = function () { function CallSiteGetFunction() {
return this.fun; return this.fun;
}; };
CallSite.prototype.getFunctionName = function () { function CallSiteGetFunctionName() {
// See if the function knows its own name // See if the function knows its own name
var name = this.fun.name; var name = this.fun.name;
if (name) { if (name) {
@ -781,7 +811,7 @@ CallSite.prototype.getFunctionName = function () {
return null; return null;
}; };
CallSite.prototype.getMethodName = function () { function CallSiteGetMethodName() {
// See if we can find a unique property on the receiver that holds // See if we can find a unique property on the receiver that holds
// this function. // this function.
var ownName = this.fun.name; var ownName = this.fun.name;
@ -811,12 +841,12 @@ CallSite.prototype.getMethodName = function () {
return null; return null;
}; };
CallSite.prototype.getFileName = function () { function CallSiteGetFileName() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script ? script.name : null; return script ? script.name : null;
}; };
CallSite.prototype.getLineNumber = function () { function CallSiteGetLineNumber() {
if (this.pos == -1) { if (this.pos == -1) {
return null; return null;
} }
@ -828,7 +858,7 @@ CallSite.prototype.getLineNumber = function () {
return location ? location.line + 1 : null; return location ? location.line + 1 : null;
}; };
CallSite.prototype.getColumnNumber = function () { function CallSiteGetColumnNumber() {
if (this.pos == -1) { if (this.pos == -1) {
return null; return null;
} }
@ -840,16 +870,16 @@ CallSite.prototype.getColumnNumber = function () {
return location ? location.column + 1: null; return location ? location.column + 1: null;
}; };
CallSite.prototype.isNative = function () { function CallSiteIsNative() {
var script = %FunctionGetScript(this.fun); var script = %FunctionGetScript(this.fun);
return script ? (script.type == TYPE_NATIVE) : false; return script ? (script.type == TYPE_NATIVE) : false;
}; };
CallSite.prototype.getPosition = function () { function CallSiteGetPosition() {
return this.pos; return this.pos;
}; };
CallSite.prototype.isConstructor = function () { function CallSiteIsConstructor() {
var constructor = this.receiver ? this.receiver.constructor : null; var constructor = this.receiver ? this.receiver.constructor : null;
if (!constructor) { if (!constructor) {
return false; return false;
@ -857,6 +887,25 @@ CallSite.prototype.isConstructor = function () {
return this.fun === constructor; 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) { function FormatEvalOrigin(script) {
var sourceURL = script.nameOrSourceURL(); var sourceURL = script.nameOrSourceURL();
if (sourceURL) { if (sourceURL) {
@ -998,63 +1047,6 @@ function FormatRawStackTrace(error, raw_stack) {
} }
} }
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) { function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit; var stackTraceLimit = $Error.stackTraceLimit;
@ -1070,52 +1062,100 @@ function captureStackTrace(obj, cons_opt) {
}); });
}; };
$Math.__proto__ = global.Object.prototype;
// DefineError is a native function. Use explicit receiver. Otherwise function SetUpError() {
// the receiver will be 'undefined'. // Define special error type constructors.
this.DefineError(function Error() { });
this.DefineError(function TypeError() { }); function DefineError(f) {
this.DefineError(function RangeError() { }); // Store the error function in both the global object
this.DefineError(function SyntaxError() { }); // and the runtime object. The function is fetched
this.DefineError(function ReferenceError() { }); // from the runtime object when throwing errors from
this.DefineError(function EvalError() { }); // within the runtime system to avoid strange side
this.DefineError(function URIError() { }); // 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);
}
});
}
$Error.captureStackTrace = captureStackTrace; DefineError(function Error() { });
DefineError(function TypeError() { });
DefineError(function RangeError() { });
DefineError(function SyntaxError() { });
DefineError(function ReferenceError() { });
DefineError(function EvalError() { });
DefineError(function URIError() { });
}
// Setup extra properties of the Error.prototype object. SetUpError();
function setErrorMessage() {
var desc = {value: '',
enumerable: false,
configurable: true,
writable: true };
DefineOwnProperty($Error.prototype,
'message',
ToPropertyDescriptor(desc),
true);
} $Error.captureStackTrace = captureStackTrace;
setErrorMessage(); %SetProperty($Error.prototype, 'message', '', DONT_ENUM);
// Global list of error objects visited during errorToString. This is // Global list of error objects visited during errorToString. This is
// used to detect cycles in error toString formatting. // used to detect cycles in error toString formatting.
var visited_errors = new $Array(); const visited_errors = new InternalArray();
var cyclic_error_marker = new $Object(); const cyclic_error_marker = new $Object();
function errorToStringDetectCycle() { function errorToStringDetectCycle(error) {
if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker; if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
try { try {
var type = this.type; var type = error.type;
if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) { var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
var formatted = FormatMessage(%NewMessageObject(type, this.arguments)); if (type && !hasMessage) {
return this.name + ": " + formatted; var formatted = FormatMessage(%NewMessageObject(type, error.arguments));
return error.name + ": " + formatted;
} }
var message = %_CallFunction(this, "message", ObjectHasOwnProperty) var message = hasMessage ? (": " + error.message) : "";
? (": " + this.message) return error.name + message;
: "";
return this.name + message;
} finally { } finally {
visited_errors.length = visited_errors.length - 1; visited_errors.length = visited_errors.length - 1;
} }
@ -1131,7 +1171,7 @@ function errorToString() {
function isCyclicErrorMarker(o) { return o === cyclic_error_marker; } function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
try { try {
return %_CallFunction(this, errorToStringDetectCycle); return errorToStringDetectCycle(this);
} catch(e) { } catch(e) {
// If this error message was encountered already return the empty // If this error message was encountered already return the empty
// string for it instead of recursively formatting it. // string for it instead of recursively formatting it.

46
deps/v8/src/mips/assembler-mips.cc

@ -49,11 +49,47 @@ bool CpuFeatures::initialized_ = false;
unsigned CpuFeatures::supported_ = 0; unsigned CpuFeatures::supported_ = 0;
unsigned CpuFeatures::found_by_runtime_probing_ = 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() { void CpuFeatures::Probe() {
ASSERT(!initialized_); ASSERT(!initialized_);
#ifdef DEBUG #ifdef DEBUG
initialized_ = true; initialized_ = true;
#endif #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 // If the compiler is allowed to use fpu then we can use fpu too in our
// code generation. // code generation.
#if !defined(__mips__) #if !defined(__mips__)
@ -62,11 +98,7 @@ void CpuFeatures::Probe() {
supported_ |= 1u << FPU; supported_ |= 1u << FPU;
} }
#else #else
if (Serializer::enabled()) { // Probe for additional features not already known to be available.
supported_ |= OS::CpuFeaturesImpliedByPlatform();
return; // No features if we might serialize.
}
if (OS::MipsCpuHasFeature(FPU)) { if (OS::MipsCpuHasFeature(FPU)) {
// This implementation also sets the FPU flags if // This implementation also sets the FPU flags if
// runtime detection of FPU returns true. // runtime detection of FPU returns true.
@ -780,10 +812,10 @@ void Assembler::bind(Label* L) {
void Assembler::next(Label* L) { void Assembler::next(Label* L) {
ASSERT(L->is_linked()); ASSERT(L->is_linked());
int link = target_at(L->pos()); int link = target_at(L->pos());
ASSERT(link > 0 || link == kEndOfChain);
if (link == kEndOfChain) { if (link == kEndOfChain) {
L->Unuse(); L->Unuse();
} else if (link > 0) { } else {
ASSERT(link >= 0);
L->link_to(link); L->link_to(link);
} }
} }

12
deps/v8/src/mips/builtins-mips.cc

@ -210,7 +210,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// Allocate the JSArray object together with space for a FixedArray with the // Allocate the JSArray object together with space for a FixedArray with the
// requested number of elements. // requested number of elements.
__ bind(&not_empty); __ bind(&not_empty);
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ li(elements_array_end, __ li(elements_array_end,
(JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize); (JSArray::kSize + FixedArray::kHeaderSize) / kPointerSize);
__ sra(scratch1, array_size, kSmiTagSize); __ sra(scratch1, array_size, kSmiTagSize);
@ -261,7 +261,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// Length of the FixedArray is the number of pre-allocated elements if // 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 // 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. // 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))); __ li(at, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
__ movz(array_size, at, array_size); __ movz(array_size, at, array_size);
@ -273,7 +273,7 @@ static void AllocateJSArray(MacroAssembler* masm,
// result: JSObject // result: JSObject
// elements_array_storage: elements array element storage // elements_array_storage: elements array element storage
// array_size: smi-tagged size of elements array // 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); __ sll(elements_array_end, array_size, kPointerSizeLog2 - kSmiTagSize);
__ Addu(elements_array_end, elements_array_storage, elements_array_end); __ Addu(elements_array_end, elements_array_storage, elements_array_end);
@ -336,14 +336,14 @@ static void ArrayNativeCode(MacroAssembler* masm,
__ bind(&argc_one_or_more); __ bind(&argc_one_or_more);
__ Branch(&argc_two_or_more, ne, a0, Operand(1)); __ 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. __ lw(a2, MemOperand(sp)); // Get the argument from the stack.
__ And(a3, a2, Operand(kIntptrSignBit | kSmiTagMask)); __ And(a3, a2, Operand(kIntptrSignBit | kSmiTagMask));
__ Branch(call_generic_code, eq, a3, Operand(zero_reg)); __ Branch(call_generic_code, eq, a3, Operand(zero_reg));
// Handle construction of an empty array of a certain size. Bail out if size // Handle construction of an empty array of a certain size. Bail out if size
// is too large to actually allocate an elements array. // is too large to actually allocate an elements array.
ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTag == 0);
__ Branch(call_generic_code, Ugreater_equal, a2, __ Branch(call_generic_code, Ugreater_equal, a2,
Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize)); Operand(JSObject::kInitialMaxFastElementArray << kSmiTagSize));
@ -576,7 +576,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// Is it a String? // Is it a String?
__ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset)); __ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
__ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset)); __ lbu(a3, FieldMemOperand(a2, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0); STATIC_ASSERT(kNotStringTag != 0);
__ And(t0, a3, Operand(kIsNotStringMask)); __ And(t0, a3, Operand(kIsNotStringMask));
__ Branch(&convert_argument, ne, t0, Operand(zero_reg)); __ Branch(&convert_argument, ne, t0, Operand(zero_reg));
__ mov(argument, a0); __ mov(argument, a0);

238
deps/v8/src/mips/code-stubs-mips.cc

@ -3538,7 +3538,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
const int kNumInstructionsToJump = 6; const int kNumInstructionsToJump = 6;
masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize); masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize);
masm->sw(ra, MemOperand(sp)); // This spot was reserved in EnterExitFrame. 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. // Stack is still aligned.
// Call the C routine. // Call the C routine.
@ -3551,7 +3551,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
} }
// Restore stack (remove arg slots). // Restore stack (remove arg slots).
__ Addu(sp, sp, StandardFrameConstants::kCArgsSlotsSize); __ Addu(sp, sp, kCArgsSlotsSize);
if (always_allocate) { if (always_allocate) {
// It's okay to clobber a2 and a3 here. v0 & v1 contain result. // It's okay to clobber a2 and a3 here. v0 & v1 contain result.
@ -3695,9 +3695,19 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Save callee saved registers on the stack. // Save callee saved registers on the stack.
__ MultiPush(kCalleeSaved | ra.bit()); __ MultiPush(kCalleeSaved | ra.bit());
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatures::Scope scope(FPU);
// Save callee-saved FPU registers.
__ MultiPushFPU(kCalleeSavedFPU);
}
// Load argv in s0 register. // Load argv in s0 register.
__ lw(s0, MemOperand(sp, (kNumCalleeSaved + 1) * kPointerSize + int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
StandardFrameConstants::kCArgsSlotsSize)); if (CpuFeatures::IsSupported(FPU)) {
offset_to_argv += kNumCalleeSavedFPU * kDoubleSize;
}
__ lw(s0, MemOperand(sp, offset_to_argv + kCArgsSlotsSize));
// We build an EntryFrame. // We build an EntryFrame.
__ li(t3, Operand(-1)); // Push a bad frame pointer to fail if it is used. __ li(t3, Operand(-1)); // Push a bad frame pointer to fail if it is used.
@ -3829,6 +3839,12 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
// Reset the stack to the callee saved registers. // Reset the stack to the callee saved registers.
__ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset); __ 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. // Restore callee saved registers from the stack.
__ MultiPop(kCalleeSaved | ra.bit()); __ MultiPop(kCalleeSaved | ra.bit());
// Return. // Return.
@ -4527,9 +4543,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset)); __ lw(a0, FieldMemOperand(subject, HeapObject::kMapOffset));
__ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset)); __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
// First check for flat string. // First check for flat string.
__ And(at, a0, Operand(kIsNotStringMask | kStringRepresentationMask)); __ And(a1, a0, Operand(kIsNotStringMask | kStringRepresentationMask));
STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
__ Branch(&seq_string, eq, at, Operand(zero_reg)); __ Branch(&seq_string, eq, a1, Operand(zero_reg));
// subject: Subject string // subject: Subject string
// a0: instance type if Subject string // a0: instance type if Subject string
@ -4541,10 +4557,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// a sequential string or an external string. // a sequential string or an external string.
// In the case of a sliced string its offset has to be taken into account. // In the case of a sliced string its offset has to be taken into account.
Label cons_string, check_encoding; Label cons_string, check_encoding;
STATIC_ASSERT((kConsStringTag < kExternalStringTag)); STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
__ Branch(&cons_string, lt, at, Operand(kExternalStringTag)); __ Branch(&cons_string, lt, a1, Operand(kExternalStringTag));
__ Branch(&runtime, eq, at, Operand(kExternalStringTag)); __ Branch(&runtime, eq, a1, Operand(kExternalStringTag));
// String is sliced. // String is sliced.
__ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset)); __ lw(t0, FieldMemOperand(subject, SlicedString::kOffsetOffset));
@ -4652,7 +4668,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// frame. Therefore we have to use fp, which points exactly to two pointer // 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 // 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.) // 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. // If slice offset is not 0, load the length from the original sliced string.
// Argument 4, a3: End of string data // Argument 4, a3: End of string data
// Argument 3, a2: Start of string data // Argument 3, a2: Start of string data
@ -4662,7 +4678,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ sllv(t1, a1, a3); __ sllv(t1, a1, a3);
__ addu(a2, t0, t1); __ addu(a2, t0, t1);
__ lw(t2, FieldMemOperand(a0, String::kLengthOffset)); __ lw(t2, FieldMemOperand(subject, String::kLengthOffset));
__ sra(t2, t2, kSmiTagSize); __ sra(t2, t2, kSmiTagSize);
__ sllv(t1, t2, a3); __ sllv(t1, t2, a3);
__ addu(a3, t0, t1); __ addu(a3, t0, t1);
@ -4670,7 +4686,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
// Already there // Already there
// Argument 1 (a0): Subject string. // Argument 1 (a0): Subject string.
// Already there __ mov(a0, subject);
// Locate the code entry and call it. // Locate the code entry and call it.
__ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag)); __ Addu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
@ -4688,13 +4704,13 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
Label success; Label success;
__ Branch(&success, eq, __ Branch(&success, eq,
subject, Operand(NativeRegExpMacroAssembler::SUCCESS)); v0, Operand(NativeRegExpMacroAssembler::SUCCESS));
Label failure; Label failure;
__ Branch(&failure, eq, __ 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. // If not exception it can only be retry. Handle that in the runtime system.
__ Branch(&runtime, ne, __ Branch(&runtime, ne,
subject, Operand(NativeRegExpMacroAssembler::EXCEPTION)); v0, Operand(NativeRegExpMacroAssembler::EXCEPTION));
// Result must now be exception. If there is no pending exception already a // 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 // stack overflow (on the backtrack stack) was detected in RegExp code but
// haven't created the exception yet. Handle that in the runtime system. // haven't created the exception yet. Handle that in the runtime system.
@ -4705,16 +4721,16 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address, __ li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address,
masm->isolate()))); masm->isolate())));
__ lw(v0, MemOperand(a2, 0)); __ 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. __ sw(a1, MemOperand(a2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable. // Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(a0, Heap::kTerminationExceptionRootIndex); __ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
Label termination_exception; 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); __ bind(&termination_exception);
__ ThrowUncatchable(TERMINATION, v0); // Expects thrown value in v0. __ ThrowUncatchable(TERMINATION, v0); // Expects thrown value in v0.
@ -5025,8 +5041,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Handle non-flat strings. // Handle non-flat strings.
__ And(result_, result_, Operand(kStringRepresentationMask)); __ And(result_, result_, Operand(kStringRepresentationMask));
STATIC_ASSERT((kConsStringTag < kExternalStringTag)); STATIC_ASSERT(kConsStringTag < kExternalStringTag);
STATIC_ASSERT((kSlicedStringTag > kExternalStringTag)); STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
__ Branch(&sliced_string, gt, result_, Operand(kExternalStringTag)); __ Branch(&sliced_string, gt, result_, Operand(kExternalStringTag));
__ Branch(&call_runtime_, eq, result_, Operand(kExternalStringTag)); __ Branch(&call_runtime_, eq, result_, Operand(kExternalStringTag));
@ -5062,7 +5078,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
// Check for 1-byte or 2-byte string. // Check for 1-byte or 2-byte string.
__ bind(&flat_string); __ bind(&flat_string);
STATIC_ASSERT(kAsciiStringTag != 0); STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ And(t0, result_, Operand(kStringEncodingMask)); __ And(t0, result_, Operand(kStringEncodingMask));
__ Branch(&ascii_string, ne, t0, Operand(zero_reg)); __ Branch(&ascii_string, ne, t0, Operand(zero_reg));
@ -5625,11 +5642,6 @@ void SubStringStub::Generate(MacroAssembler* masm) {
Register to = t2; Register to = t2;
Register from = t3; 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. // Check bounds and smi-ness.
__ lw(to, MemOperand(sp, kToOffset)); __ lw(to, MemOperand(sp, kToOffset));
__ lw(from, MemOperand(sp, kFromOffset)); __ lw(from, MemOperand(sp, kFromOffset));
@ -5653,7 +5665,8 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Special handling of sub-strings of length 1 and 2. One character strings // 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 // 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)); __ Branch(&sub_string_runtime, lt, a2, Operand(2));
// Both to and from are smis. // Both to and from are smis.
@ -5665,19 +5678,32 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// t5: to index (untagged smi) // t5: to index (untagged smi)
// Make sure first argument is a sequential (or flat) string. // Make sure first argument is a sequential (or flat) string.
__ lw(t1, MemOperand(sp, kStringOffset)); __ lw(v0, MemOperand(sp, kStringOffset));
__ Branch(&sub_string_runtime, eq, t1, Operand(kSmiTagMask)); __ 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)); __ 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)); __ 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 // a1: instance type
// a2: result string length // a2: result string length
// a3: from index (untagged smi) // a3: from index (untagged smi)
// t1: string
// t2: (a.k.a. to): to (smi) // t2: (a.k.a. to): to (smi)
// t3: (a.k.a. from): from offset (smi) // t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi) // t5: to index (untagged smi)
@ -5686,8 +5712,9 @@ void SubStringStub::Generate(MacroAssembler* masm) {
__ And(t0, a1, Operand(kStringRepresentationMask)); __ And(t0, a1, Operand(kStringRepresentationMask));
STATIC_ASSERT(kSeqStringTag < kConsStringTag); STATIC_ASSERT(kSeqStringTag < kConsStringTag);
STATIC_ASSERT(kConsStringTag < kExternalStringTag); 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)); __ Branch(&sub_string_runtime, gt, t0, Operand(kConsStringTag));
// Sequential strings are handled directly. // Sequential strings are handled directly.
@ -5696,32 +5723,32 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Cons string. Try to recurse (once) on the first substring. // Cons string. Try to recurse (once) on the first substring.
// (This adds a little more generality than necessary to handle flattened // (This adds a little more generality than necessary to handle flattened
// cons strings, but not much). // cons strings, but not much).
__ lw(t1, FieldMemOperand(t1, ConsString::kFirstOffset)); __ lw(v0, FieldMemOperand(v0, ConsString::kFirstOffset));
__ lw(t0, FieldMemOperand(t1, HeapObject::kMapOffset)); __ lw(t0, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(a1, FieldMemOperand(t0, Map::kInstanceTypeOffset)); __ lbu(a1, FieldMemOperand(t0, Map::kInstanceTypeOffset));
STATIC_ASSERT(kSeqStringTag == 0); 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)); __ Branch(&sub_string_runtime, ne, a1, Operand(kStringRepresentationMask));
// Definitly a sequential string. // Definitly a sequential string.
__ bind(&seq_string); __ bind(&seq_string);
// v0: original string
// a1: instance type // a1: instance type
// a2: result string length // a2: result string length
// a3: from index (untagged smi) // a3: from index (untagged smi)
// t1: string
// t2: (a.k.a. to): to (smi) // t2: (a.k.a. to): to (smi)
// t3: (a.k.a. from): from offset (smi) // t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged 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. __ Branch(&sub_string_runtime, lt, t0, Operand(to)); // Fail if to > length.
to = no_reg; to = no_reg;
// v0: original string or left hand side of the original cons string.
// a1: instance type // a1: instance type
// a2: result string length // a2: result string length
// a3: from index (untagged smi) // a3: from index (untagged smi)
// t1: string
// t3: (a.k.a. from): from offset (smi) // t3: (a.k.a. from): from offset (smi)
// t5: to index (untagged smi) // t5: to index (untagged smi)
@ -5737,84 +5764,147 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Sub string of length 2 requested. // Sub string of length 2 requested.
// Get the two characters forming the sub string. // Get the two characters forming the sub string.
__ Addu(t1, t1, Operand(a3)); __ Addu(v0, v0, Operand(a3));
__ lbu(a3, FieldMemOperand(t1, SeqAsciiString::kHeaderSize)); __ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
__ lbu(t0, FieldMemOperand(t1, SeqAsciiString::kHeaderSize + 1)); __ lbu(t0, FieldMemOperand(v0, SeqAsciiString::kHeaderSize + 1));
// Try to lookup two character string in symbol table. // Try to lookup two character string in symbol table.
Label make_two_character_string; Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe( StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string); masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string);
Counters* counters = masm->isolate()->counters(); Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->sub_string_native(), 1, a3, t0); __ jmp(&return_v0);
__ Addu(sp, sp, Operand(3 * kPointerSize));
__ Ret();
// a2: result string length. // a2: result string length.
// a3: two characters combined into halfword in little endian byte order. // a3: two characters combined into halfword in little endian byte order.
__ bind(&make_two_character_string); __ bind(&make_two_character_string);
__ AllocateAsciiString(v0, a2, t0, t1, t4, &sub_string_runtime); __ AllocateAsciiString(v0, a2, t0, t1, t4, &sub_string_runtime);
__ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize)); __ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
__ IncrementCounter(counters->sub_string_native(), 1, a3, t0); __ jmp(&return_v0);
__ Addu(sp, sp, Operand(3 * kPointerSize));
__ Ret();
__ bind(&result_longer_than_two); __ 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. // Allocate the result.
__ AllocateAsciiString(v0, a2, t4, t0, a1, &sub_string_runtime); __ AllocateAsciiString(v0, a2, t4, t0, a1, &sub_string_runtime);
// v0: result string. // v0: result string
// a2: result string length. // a2: result string length
// a3: from index (untagged smi) // a3: from index (untagged smi)
// t1: string. // t1: first character of substring to copy
// t3: (a.k.a. from): from offset (smi) // t3: (a.k.a. from): from offset (smi)
// Locate first character of result. // Locate first character of result.
__ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); __ 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. // v0: result string
// a1: first character of result string. // a1: first character of result string
// a2: result string length. // a2: result string length
// t1: first character of sub string to copy. // t1: first character of substring to copy
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong( StringHelper::GenerateCopyCharactersLong(
masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED); masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED);
__ IncrementCounter(counters->sub_string_native(), 1, a3, t0); __ jmp(&return_v0);
__ Addu(sp, sp, Operand(3 * kPointerSize));
__ Ret();
__ bind(&non_ascii_flat); __ bind(&non_ascii_flat);
// a2: result string length. // a2: result string length
// t1: string. // t1: string
// t3: (a.k.a. from): from offset (smi) // t3: (a.k.a. from): from offset (smi)
// Check for flat two byte string. // 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. // Allocate the result.
__ AllocateTwoByteString(v0, a2, a1, a3, t0, &sub_string_runtime); __ AllocateTwoByteString(v0, a2, a1, a3, t0, &sub_string_runtime);
// v0: result string. // v0: result string
// a2: result string length. // a2: result string length
// t1: string. // t1: first character of substring to copy
// Locate first character of result. // Locate first character of result.
__ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); __ 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; from = no_reg;
// v0: result string. // v0: result string.
// a1: first character of result. // a1: first character of result.
// a2: result length. // a2: result length.
// t1: first character of string to copy. // t1: first character of substring to copy.
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong( StringHelper::GenerateCopyCharactersLong(
masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED); 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); __ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
__ Addu(sp, sp, Operand(3 * kPointerSize)); __ Addu(sp, sp, Operand(3 * kPointerSize));
__ Ret(); __ Ret();

6
deps/v8/src/mips/constants-mips.h

@ -743,11 +743,9 @@ class Instruction {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// MIPS assembly various constants. // MIPS assembly various constants.
static const int kArgsSlotsSize = 4 * Instruction::kInstrSize;
static const int kArgsSlotsNum = 4;
// C/C++ argument slots size. // 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. // JS argument slots size.
static const int kJSArgsSlotsSize = 0 * Instruction::kInstrSize; static const int kJSArgsSlotsSize = 0 * Instruction::kInstrSize;
// Assembly builtins argument slots size. // Assembly builtins argument slots size.

113
deps/v8/src/mips/frames-mips.h

@ -30,7 +30,6 @@
#ifndef V8_MIPS_FRAMES_MIPS_H_ #ifndef V8_MIPS_FRAMES_MIPS_H_
#define V8_MIPS_FRAMES_MIPS_H_ #define V8_MIPS_FRAMES_MIPS_H_
namespace v8 { namespace v8 {
namespace internal { namespace internal {
@ -40,13 +39,22 @@ namespace internal {
static const int kNumRegs = 32; static const int kNumRegs = 32;
static const RegList kJSCallerSaved = static const RegList kJSCallerSaved =
1 << 2 | // v0 1 << 2 | // v0
1 << 4 | // a0 1 << 3 | // v1
1 << 5 | // a1 1 << 4 | // a0
1 << 6 | // a2 1 << 5 | // a1
1 << 7; // a3 1 << 6 | // a2
1 << 7 | // a3
static const int kNumJSCallerSaved = 5; 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 = 14;
// Return the code of the n-th caller-saved register available to JavaScript // Return the code of the n-th caller-saved register available to JavaScript
@ -56,19 +64,31 @@ int JSCallerSavedCode(int n);
// Callee-saved registers preserved when switching from C to JavaScript. // Callee-saved registers preserved when switching from C to JavaScript.
static const RegList kCalleeSaved = static const RegList kCalleeSaved =
// Saved temporaries. 1 << 16 | // s0
1 << 16 | 1 << 17 | 1 << 18 | 1 << 19 | 1 << 17 | // s1
1 << 20 | 1 << 21 | 1 << 22 | 1 << 23 | 1 << 18 | // s2
// fp. 1 << 19 | // s3
1 << 30; 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 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 // Number of registers for which space is reserved in safepoints. Must be a
// multiple of 8. // multiple of 8.
// TODO(mips): Only 8 registers may actually be sufficient. Revisit. // 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. // Define the list of registers actually saved at safepoints.
// Note that the number of saved registers may be smaller than the reserved // Note that the number of saved registers may be smaller than the reserved
@ -82,37 +102,37 @@ typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
static const int kUndefIndex = -1; static const int kUndefIndex = -1;
// Map with indexes on stack that corresponds to codes of saved registers. // Map with indexes on stack that corresponds to codes of saved registers.
static const int kSafepointRegisterStackIndexMap[kNumRegs] = { static const int kSafepointRegisterStackIndexMap[kNumRegs] = {
kUndefIndex, kUndefIndex, // zero_reg
kUndefIndex, kUndefIndex, // at
0, // v0 0, // v0
kUndefIndex, 1, // v1
1, // a0 2, // a0
2, // a1 3, // a1
3, // a2 4, // a2
4, // a3 5, // a3
kUndefIndex, 6, // t0
kUndefIndex, 7, // t1
kUndefIndex, 8, // t2
kUndefIndex, 9, // t3
kUndefIndex, 10, // t4
kUndefIndex, 11, // t5
kUndefIndex, 12, // t6
kUndefIndex, 13, // t7
5, // Saved temporaries. 14, // s0
6, 15, // s1
7, 16, // s2
8, 17, // s3
9, 18, // s4
10, 19, // s5
11, 20, // s6
12, 21, // s7
kUndefIndex, kUndefIndex, // t8
kUndefIndex, kUndefIndex, // t9
kUndefIndex, kUndefIndex, // k0
kUndefIndex, kUndefIndex, // k1
13, // gp kUndefIndex, // gp
14, // sp kUndefIndex, // sp
15, // fp 22, // fp
kUndefIndex kUndefIndex
}; };
@ -174,9 +194,6 @@ class StandardFrameConstants : public AllStatic {
static const int kRArgsSlotsSize = 4 * kPointerSize; static const int kRArgsSlotsSize = 4 * kPointerSize;
static const int kRegularArgsSlotsSize = kRArgsSlotsSize; 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. // JS argument slots size.
static const int kJSArgsSlotsSize = 0 * kPointerSize; static const int kJSArgsSlotsSize = 0 * kPointerSize;
// Assembly builtins argument slots size. // Assembly builtins argument slots size.

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

@ -200,7 +200,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
// Copy any necessary parameters into the context. // Copy any necessary parameters into the context.
int num_parameters = info->scope()->num_parameters(); int num_parameters = info->scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) { for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot(); Slot* slot = scope()->parameter(i)->rewrite();
if (slot != NULL && slot->type() == Slot::CONTEXT) { if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize; (num_parameters - 1 - i) * kPointerSize;
@ -252,7 +252,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
ArgumentsAccessStub stub(type); ArgumentsAccessStub stub(type);
__ CallStub(&stub); __ CallStub(&stub);
Move(arguments->AsSlot(), v0, a1, a2); Move(arguments->rewrite(), v0, a1, a2);
} }
if (FLAG_trace) { if (FLAG_trace) {
@ -266,6 +266,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
scope()->VisitIllegalRedeclaration(this); scope()->VisitIllegalRedeclaration(this);
} else { } else {
PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
{ Comment cmnt(masm_, "[ Declarations"); { Comment cmnt(masm_, "[ Declarations");
// For named function expressions, declare the function name as a // For named function expressions, declare the function name as a
// constant. // constant.
@ -276,7 +277,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
} }
{ Comment cmnt(masm_, "[ Stack check"); { Comment cmnt(masm_, "[ Stack check");
PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
Label ok; Label ok;
__ LoadRoot(t0, Heap::kStackLimitRootIndex); __ LoadRoot(t0, Heap::kStackLimitRootIndex);
__ Branch(&ok, hs, sp, Operand(t0)); __ Branch(&ok, hs, sp, Operand(t0));
@ -632,6 +633,7 @@ MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
return ContextOperand(scratch, slot->index()); return ContextOperand(scratch, slot->index());
} }
case Slot::LOOKUP: case Slot::LOOKUP:
case Slot::GLOBAL:
UNREACHABLE(); UNREACHABLE();
} }
UNREACHABLE(); UNREACHABLE();
@ -690,22 +692,23 @@ void FullCodeGenerator::Move(Slot* dst,
} }
void FullCodeGenerator::EmitDeclaration(Variable* variable, void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
Variable::Mode mode, Variable::Mode mode,
FunctionLiteral* function) { FunctionLiteral* function) {
Comment cmnt(masm_, "[ Declaration"); Comment cmnt(masm_, "[ Declaration");
Variable* variable = proxy->var();
ASSERT(variable != NULL); // Must have been resolved. ASSERT(variable != NULL); // Must have been resolved.
Slot* slot = variable->AsSlot(); Slot* slot = variable->rewrite();
ASSERT(slot != NULL); ASSERT(slot != NULL);
switch (slot->type()) { switch (slot->type()) {
case Slot::PARAMETER: case Slot::PARAMETER:
case Slot::LOCAL: case Slot::LOCAL:
if (mode == Variable::CONST) { if (function != NULL) {
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
__ sw(t0, MemOperand(fp, SlotOffset(slot)));
} else if (function != NULL) {
VisitForAccumulatorValue(function); VisitForAccumulatorValue(function);
__ sw(result_register(), MemOperand(fp, SlotOffset(slot))); __ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
} else if (mode == Variable::CONST || mode == Variable::LET) {
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
__ sw(t0, MemOperand(fp, SlotOffset(slot)));
} }
break; break;
@ -726,17 +729,19 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ Check(ne, "Declaration in catch context.", __ Check(ne, "Declaration in catch context.",
a1, Operand(t0)); a1, Operand(t0));
} }
if (mode == Variable::CONST) { if (function != NULL) {
__ 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) {
VisitForAccumulatorValue(function); VisitForAccumulatorValue(function);
__ sw(result_register(), ContextOperand(cp, slot->index())); __ sw(result_register(), ContextOperand(cp, slot->index()));
int offset = Context::SlotOffset(slot->index()); int offset = Context::SlotOffset(slot->index());
// We know that we have written a function, which is not a smi. // We know that we have written a function, which is not a smi.
__ mov(a1, cp); __ mov(a1, cp);
__ RecordWrite(a1, Operand(offset), a2, result_register()); __ RecordWrite(a1, Operand(offset), a2, result_register());
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} else if (mode == Variable::CONST || mode == Variable::LET) {
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ sw(at, ContextOperand(cp, slot->index()));
// No write barrier since the_hole_value is in old space.
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
} }
break; break;
@ -752,13 +757,13 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
// Note: For variables we must not push an initial value (such as // Note: For variables we must not push an initial value (such as
// 'undefined') because we may have a (legal) redeclaration and we // 'undefined') because we may have a (legal) redeclaration and we
// must not destroy the current value. // must not destroy the current value.
if (mode == Variable::CONST) { if (function != NULL) {
__ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
__ Push(cp, a2, a1, a0);
} else if (function != NULL) {
__ Push(cp, a2, a1); __ Push(cp, a2, a1);
// Push initial value for function declaration. // Push initial value for function declaration.
VisitForStackValue(function); VisitForStackValue(function);
} else if (mode == Variable::CONST || mode == Variable::LET) {
__ LoadRoot(a0, Heap::kTheHoleValueRootIndex);
__ Push(cp, a2, a1, a0);
} else { } else {
ASSERT(Smi::FromInt(0) == 0); ASSERT(Smi::FromInt(0) == 0);
// No initial value! // No initial value!
@ -768,23 +773,25 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ CallRuntime(Runtime::kDeclareContextSlot, 4); __ CallRuntime(Runtime::kDeclareContextSlot, 4);
break; break;
} }
case Slot::GLOBAL:
UNREACHABLE();
} }
} }
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
} }
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
// Call the runtime to declare the globals. // Call the runtime to declare the globals.
// The context is the first argument. // The context is the first argument.
__ li(a2, Operand(pairs)); __ li(a1, Operand(pairs));
__ li(a1, Operand(Smi::FromInt(is_eval() ? 1 : 0))); __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
__ li(a0, Operand(Smi::FromInt(strict_mode_flag()))); __ Push(cp, a1, a0);
__ Push(cp, a2, a1, a0); __ CallRuntime(Runtime::kDeclareGlobals, 3);
__ CallRuntime(Runtime::kDeclareGlobals, 4);
// Return value is ignored. // Return value is ignored.
} }
@ -1189,7 +1196,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
__ Branch(done); __ Branch(done);
} else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); Slot* potential_slot = slot->var()->local_if_not_shadowed()->rewrite();
Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
if (potential_slot != NULL) { if (potential_slot != NULL) {
// Generate fast case for locals that rewrite to slots. // Generate fast case for locals that rewrite to slots.
@ -1215,7 +1222,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
// variables. Then load the argument from the arguments // variables. Then load the argument from the arguments
// object using keyed load. // object using keyed load.
__ lw(a1, __ lw(a1,
ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), ContextSlotOperandCheckExtensions(obj_proxy->var()->rewrite(),
slow)); slow));
__ li(a0, Operand(key_literal->handle())); __ li(a0, Operand(key_literal->handle()));
Handle<Code> ic = Handle<Code> ic =
@ -1236,7 +1243,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
// Three cases: non-this global variables, lookup slots, and all other // Three cases: non-this global variables, lookup slots, and all other
// types of slots. // types of slots.
Slot* slot = var->AsSlot(); Slot* slot = var->rewrite();
ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
if (slot == NULL) { if (slot == NULL) {
@ -1279,9 +1286,22 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
__ LoadRoot(a0, Heap::kUndefinedValueRootIndex); __ LoadRoot(a0, Heap::kUndefinedValueRootIndex);
__ movz(v0, a0, at); // Conditional move. __ movz(v0, a0, at); // Conditional move.
context()->Plug(v0); context()->Plug(v0);
} else { } else if (var->mode() == Variable::LET) {
context()->Plug(slot); // Let bindings may be the hole value if they have not been initialized.
} // Throw a type error in this case.
Label done;
MemOperand slot_operand = EmitSlotSearch(slot, a0);
__ lw(v0, slot_operand);
__ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
__ Branch(&done, ne, v0, Operand(a1));
__ li(v0, Operand(var->name()));
__ push(v0);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
__ bind(&done);
context()->Plug(v0);
} else {
context()->Plug(slot);
}
} }
} }
@ -1500,9 +1520,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Update the write barrier for the array store with v0 as the scratch // Update the write barrier for the array store with v0 as the scratch
// register. // register.
__ li(a2, Operand(offset)); __ RecordWrite(a1, Operand(offset), a2, result_register());
// TODO(PJ): double check this RecordWrite call.
__ RecordWrite(a1, a2, result_register());
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
} }
@ -1822,7 +1840,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
void FullCodeGenerator::EmitVariableAssignment(Variable* var, void FullCodeGenerator::EmitVariableAssignment(Variable* var,
Token::Value op) { Token::Value op) {
ASSERT(var != NULL); ASSERT(var != NULL);
ASSERT(var->is_global() || var->AsSlot() != NULL); ASSERT(var->is_global() || var->rewrite() != NULL);
if (var->is_global()) { if (var->is_global()) {
ASSERT(!var->is_this()); ASSERT(!var->is_this());
@ -1842,7 +1860,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// scope. However, unlike var initializers, const initializers are able // scope. However, unlike var initializers, const initializers are able
// to drill a hole to that function context, even from inside a 'with' // to drill a hole to that function context, even from inside a 'with'
// context. We thus bypass the normal static scope lookup. // context. We thus bypass the normal static scope lookup.
Slot* slot = var->AsSlot(); Slot* slot = var->rewrite();
Label skip; Label skip;
switch (slot->type()) { switch (slot->type()) {
case Slot::PARAMETER: case Slot::PARAMETER:
@ -1863,13 +1881,65 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Push(cp, a0); // Context and name. __ Push(cp, a0); // Context and name.
__ CallRuntime(Runtime::kInitializeConstContextSlot, 3); __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
break; break;
case Slot::GLOBAL:
UNREACHABLE();
} }
__ bind(&skip); __ bind(&skip);
} else if (var->mode() == Variable::LET && op != Token::INIT_LET) {
// Perform the assignment for non-const variables. Const assignments
// are simply skipped.
Slot* slot = var->AsSlot();
switch (slot->type()) {
case Slot::PARAMETER:
case Slot::LOCAL: {
Label assign;
// Check for an initialized let binding.
__ lw(a1, MemOperand(fp, SlotOffset(slot)));
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
__ Branch(&assign, ne, a1, Operand(t0));
__ li(a1, Operand(var->name()));
__ push(a1);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
// Perform the assignment.
__ bind(&assign);
__ sw(result_register(), MemOperand(fp, SlotOffset(slot)));
break;
}
case Slot::CONTEXT: {
// Let variables may be the hole value if they have not been
// initialized. Throw a type error in this case.
Label assign;
MemOperand target = EmitSlotSearch(slot, a1);
// Check for an initialized let binding.
__ lw(a3, target);
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
__ Branch(&assign, ne, a3, Operand(t0));
__ li(a3, Operand(var->name()));
__ push(a3);
__ CallRuntime(Runtime::kThrowReferenceError, 1);
// Perform the assignment.
__ bind(&assign);
__ sw(result_register(), target);
// RecordWrite may destroy all its register arguments.
__ mov(a3, result_register());
int offset = Context::SlotOffset(slot->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) { } else if (var->mode() != Variable::CONST) {
// Perform the assignment for non-const variables. Const assignments // Perform the assignment for non-const variables. Const assignments
// are simply skipped. // are simply skipped.
Slot* slot = var->AsSlot(); Slot* slot = var->rewrite();
switch (slot->type()) { switch (slot->type()) {
case Slot::PARAMETER: case Slot::PARAMETER:
case Slot::LOCAL: case Slot::LOCAL:
@ -1896,6 +1966,9 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
__ Push(cp, a1, a0); // Context, name, strict mode. __ Push(cp, a1, a0); // Context, name, strict mode.
__ CallRuntime(Runtime::kStoreContextSlot, 4); __ CallRuntime(Runtime::kStoreContextSlot, 4);
break; break;
case Slot::GLOBAL:
UNREACHABLE();
} }
} }
} }
@ -2115,8 +2188,13 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
int receiver_offset = 2 + info_->scope()->num_parameters(); int receiver_offset = 2 + info_->scope()->num_parameters();
__ lw(a1, MemOperand(fp, receiver_offset * kPointerSize)); __ lw(a1, MemOperand(fp, receiver_offset * kPointerSize));
__ push(a1); __ push(a1);
// Push the strict mode flag. // Push the strict mode flag. In harmony mode every eval call
__ li(a1, Operand(Smi::FromInt(strict_mode_flag()))); // 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); __ push(a1);
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
@ -2158,9 +2236,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// in generated code. If we succeed, there is no need to perform a // in generated code. If we succeed, there is no need to perform a
// context lookup in the runtime system. // context lookup in the runtime system.
Label done; Label done;
if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { if (var->rewrite() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
Label slow; Label slow;
EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), EmitLoadGlobalSlotCheckExtensions(var->rewrite(),
NOT_INSIDE_TYPEOF, NOT_INSIDE_TYPEOF,
&slow); &slow);
// Push the function and resolve eval. // Push the function and resolve eval.
@ -2198,15 +2276,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ lw(a0, GlobalObjectOperand()); __ lw(a0, GlobalObjectOperand());
__ push(a0); __ push(a0);
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
} else if (var != NULL && var->AsSlot() != NULL && } else if (var != NULL && var->rewrite() != NULL &&
var->AsSlot()->type() == Slot::LOOKUP) { var->rewrite()->type() == Slot::LOOKUP) {
// Call to a lookup slot (dynamically introduced variable). // Call to a lookup slot (dynamically introduced variable).
Label slow, done; Label slow, done;
{ PreservePositionScope scope(masm()->positions_recorder()); { PreservePositionScope scope(masm()->positions_recorder());
// Generate code for loading from variables potentially shadowed // Generate code for loading from variables potentially shadowed
// by eval-introduced variables. // by eval-introduced variables.
EmitDynamicLoadFromSlotFastCase(var->AsSlot(), EmitDynamicLoadFromSlotFastCase(var->rewrite(),
NOT_INSIDE_TYPEOF, NOT_INSIDE_TYPEOF,
&slow, &slow,
&done); &done);
@ -3208,7 +3286,7 @@ void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
Label done, not_found; Label done, not_found;
ASSERT(kSmiTag == 0 && kSmiTagSize == 1); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
__ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); __ lw(a2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
// a2 now holds finger offset as a smi. // a2 now holds finger offset as a smi.
__ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ Addu(a3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
@ -3611,8 +3689,8 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
__ Push(a2, a1, a0); __ Push(a2, a1, a0);
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
context()->Plug(v0); context()->Plug(v0);
} else if (var->AsSlot() != NULL && } else if (var->rewrite() != NULL &&
var->AsSlot()->type() != Slot::LOOKUP) { var->rewrite()->type() != Slot::LOOKUP) {
// Result of deleting non-global, non-dynamic variables is false. // Result of deleting non-global, non-dynamic variables is false.
// The subexpression does not have side effects. // The subexpression does not have side effects.
context()->Plug(false); context()->Plug(false);
@ -3902,13 +3980,13 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
PrepareForBailout(expr, TOS_REG); PrepareForBailout(expr, TOS_REG);
context()->Plug(v0); context()->Plug(v0);
} else if (proxy != NULL && } else if (proxy != NULL &&
proxy->var()->AsSlot() != NULL && proxy->var()->rewrite() != NULL &&
proxy->var()->AsSlot()->type() == Slot::LOOKUP) { proxy->var()->rewrite()->type() == Slot::LOOKUP) {
Label done, slow; Label done, slow;
// Generate code for loading from variables potentially shadowed // Generate code for loading from variables potentially shadowed
// by eval-introduced variables. // by eval-introduced variables.
Slot* slot = proxy->var()->AsSlot(); Slot* slot = proxy->var()->rewrite();
EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
__ bind(&slow); __ bind(&slow);
@ -4203,7 +4281,7 @@ void FullCodeGenerator::EnterFinallyBlock() {
// Cook return address in link register to stack (smi encoded Code* delta). // Cook return address in link register to stack (smi encoded Code* delta).
__ Subu(a1, ra, Operand(masm_->CodeObject())); __ Subu(a1, ra, Operand(masm_->CodeObject()));
ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(0 == kSmiTag);
__ Addu(a1, a1, Operand(a1)); // Convert to smi. __ Addu(a1, a1, Operand(a1)); // Convert to smi.
__ push(a1); __ push(a1);
} }
@ -4222,6 +4300,34 @@ void FullCodeGenerator::ExitFinallyBlock() {
} }
#undef __
#define __ ACCESS_MASM(masm())
FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
int* stack_depth,
int* context_length) {
// The macros used here must preserve the result register.
// Because the handler block contains the context of the finally
// code, we can restore it directly from there for the finally code
// rather than iteratively unwinding contexts via their previous
// links.
__ Drop(*stack_depth); // Down to the handler block.
if (*context_length > 0) {
// Restore the context to its dedicated register and the stack.
__ lw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
__ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
__ PopTryHandler();
__ Call(finally_entry_);
*stack_depth = 0;
*context_length = 0;
return previous_;
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

6
deps/v8/src/mips/ic-mips.cc

@ -338,7 +338,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
__ Addu(scratch1, elements, __ Addu(scratch1, elements,
Operand(FixedArray::kHeaderSize - kHeapObjectTag)); Operand(FixedArray::kHeaderSize - kHeapObjectTag));
// The key is a smi. // The key is a smi.
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(at, key, kPointerSizeLog2 - kSmiTagSize); __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
__ addu(at, at, scratch1); __ addu(at, at, scratch1);
__ lw(scratch2, MemOperand(at)); __ lw(scratch2, MemOperand(at));
@ -372,7 +372,7 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
// Is the string a symbol? // Is the string a symbol?
// map: key map // map: key map
__ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
ASSERT(kSymbolTag != 0); STATIC_ASSERT(kSymbolTag != 0);
__ And(at, hash, Operand(kIsSymbolMask)); __ And(at, hash, Operand(kIsSymbolMask));
__ Branch(not_symbol, eq, at, Operand(zero_reg)); __ Branch(not_symbol, eq, at, Operand(zero_reg));
} }
@ -1269,7 +1269,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
__ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
__ Branch(&slow, hs, key, Operand(t0)); __ Branch(&slow, hs, key, Operand(t0));
// Calculate key + 1 as smi. // Calculate key + 1 as smi.
ASSERT_EQ(0, kSmiTag); STATIC_ASSERT(0 == kSmiTag);
__ Addu(t3, key, Operand(Smi::FromInt(1))); __ Addu(t3, key, Operand(Smi::FromInt(1)));
__ sw(t3, FieldMemOperand(receiver, JSArray::kLengthOffset)); __ sw(t3, FieldMemOperand(receiver, JSArray::kLengthOffset));
__ Branch(&fast); __ Branch(&fast);

148
deps/v8/src/mips/macro-assembler-mips.cc

@ -703,52 +703,114 @@ void MacroAssembler::li(Register rd, Operand j, bool gen2instr) {
void MacroAssembler::MultiPush(RegList regs) { void MacroAssembler::MultiPush(RegList regs) {
int16_t NumSaved = 0; int16_t num_to_push = NumberOfBitsSet(regs);
int16_t NumToPush = 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--) { for (int16_t i = kNumRegisters; i > 0; i--) {
if ((regs & (1 << i)) != 0) { 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) { void MacroAssembler::MultiPushReversed(RegList regs) {
int16_t NumSaved = 0; int16_t num_to_push = NumberOfBitsSet(regs);
int16_t NumToPush = 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++) { for (int16_t i = 0; i < kNumRegisters; i++) {
if ((regs & (1 << i)) != 0) { 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) { void MacroAssembler::MultiPop(RegList regs) {
int16_t NumSaved = 0; int16_t stack_offset = 0;
for (int16_t i = 0; i < kNumRegisters; i++) { for (int16_t i = 0; i < kNumRegisters; i++) {
if ((regs & (1 << i)) != 0) { 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) { void MacroAssembler::MultiPopReversed(RegList regs) {
int16_t NumSaved = 0; int16_t stack_offset = 0;
for (int16_t i = kNumRegisters; i > 0; i--) { for (int16_t i = kNumRegisters; i > 0; i--) {
if ((regs & (1 << i)) != 0) { 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);
} }
@ -1557,12 +1619,14 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
b(offset); b(offset);
break; break;
case eq: case eq:
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
beq(rs, r2, offset); beq(rs, r2, offset);
break; break;
case ne: case ne:
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
@ -1574,6 +1638,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
bgtz(rs, offset); bgtz(rs, offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
slt(scratch, r2, rs); slt(scratch, r2, rs);
@ -1590,6 +1655,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
beq(scratch, zero_reg, offset); beq(scratch, zero_reg, offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
slt(scratch, rs, r2); slt(scratch, rs, r2);
@ -1606,6 +1672,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
bne(scratch, zero_reg, offset); bne(scratch, zero_reg, offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
slt(scratch, rs, r2); slt(scratch, rs, r2);
@ -1618,6 +1685,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
blez(rs, offset); blez(rs, offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
slt(scratch, r2, rs); slt(scratch, r2, rs);
@ -1631,6 +1699,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
bgtz(rs, offset); bgtz(rs, offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
sltu(scratch, r2, rs); sltu(scratch, r2, rs);
@ -1647,6 +1716,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
beq(scratch, zero_reg, offset); beq(scratch, zero_reg, offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
sltu(scratch, rs, r2); sltu(scratch, rs, r2);
@ -1663,6 +1733,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
bne(scratch, zero_reg, offset); bne(scratch, zero_reg, offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
sltu(scratch, rs, r2); sltu(scratch, rs, r2);
@ -1675,6 +1746,7 @@ void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
offset = shifted_branch_offset(L, false); offset = shifted_branch_offset(L, false);
b(offset); b(offset);
} else { } else {
ASSERT(!scratch.is(rs));
r2 = scratch; r2 = scratch;
li(r2, rt); li(r2, rt);
sltu(scratch, r2, rs); sltu(scratch, r2, rs);
@ -2743,6 +2815,46 @@ void MacroAssembler::AllocateAsciiConsString(Register result,
} }
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 // Allocates a heap number or jumps to the label if the young space is full and
// a scavenge is needed. // a scavenge is needed.
void MacroAssembler::AllocateHeapNumber(Register result, void MacroAssembler::AllocateHeapNumber(Register result,
@ -4141,11 +4253,9 @@ void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
// mips, even though those argument slots are not normally used. // mips, even though those argument slots are not normally used.
// Remaining arguments are pushed on the stack, above (higher address than) // Remaining arguments are pushed on the stack, above (higher address than)
// the argument slots. // the argument slots.
ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
0 : num_arguments - kRegisterPassedArguments) + 0 : num_arguments - kRegisterPassedArguments) +
(StandardFrameConstants::kCArgsSlotsSize / kCArgSlotCount;
kPointerSize);
if (frame_alignment > kPointerSize) { if (frame_alignment > kPointerSize) {
// Make stack end at alignment and make room for num_arguments - 4 words // Make stack end at alignment and make room for num_arguments - 4 words
// and the original value of sp. // and the original value of sp.
@ -4217,11 +4327,9 @@ void MacroAssembler::CallCFunctionHelper(Register function,
Call(function); Call(function);
ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0);
int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ?
0 : num_arguments - kRegisterPassedArguments) + 0 : num_arguments - kRegisterPassedArguments) +
(StandardFrameConstants::kCArgsSlotsSize / kCArgSlotCount;
kPointerSize);
if (OS::ActivationFrameAlignment() > kPointerSize) { if (OS::ActivationFrameAlignment() > kPointerSize) {
lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));

21
deps/v8/src/mips/macro-assembler-mips.h

@ -362,6 +362,16 @@ class MacroAssembler: public Assembler {
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
Label* gc_required); 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 // 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 // space is full and a scavenge is needed. All registers are clobbered also
@ -442,6 +452,9 @@ class MacroAssembler: public Assembler {
void MultiPush(RegList regs); void MultiPush(RegList regs);
void MultiPushReversed(RegList regs); void MultiPushReversed(RegList regs);
void MultiPushFPU(RegList regs);
void MultiPushReversedFPU(RegList regs);
// Lower case push() for compatibility with arch-independent code. // Lower case push() for compatibility with arch-independent code.
void push(Register src) { void push(Register src) {
Addu(sp, sp, Operand(-kPointerSize)); Addu(sp, sp, Operand(-kPointerSize));
@ -487,6 +500,9 @@ class MacroAssembler: public Assembler {
void MultiPop(RegList regs); void MultiPop(RegList regs);
void MultiPopReversed(RegList regs); void MultiPopReversed(RegList regs);
void MultiPopFPU(RegList regs);
void MultiPopReversedFPU(RegList regs);
// Lower case pop() for compatibility with arch-independent code. // Lower case pop() for compatibility with arch-independent code.
void pop(Register dst) { void pop(Register dst) {
lw(dst, MemOperand(sp, 0)); lw(dst, MemOperand(sp, 0));
@ -1197,10 +1213,9 @@ static inline MemOperand FieldMemOperand(Register object, int offset) {
// Generate a MemOperand for storing arguments 5..N on the stack // Generate a MemOperand for storing arguments 5..N on the stack
// when calling CallCFunction(). // when calling CallCFunction().
static inline MemOperand CFunctionArgumentOperand(int index) { static inline MemOperand CFunctionArgumentOperand(int index) {
ASSERT(index > StandardFrameConstants::kCArgSlotCount); ASSERT(index > kCArgSlotCount);
// Argument 5 takes the slot just past the four Arg-slots. // Argument 5 takes the slot just past the four Arg-slots.
int offset = int offset = (index - 5) * kPointerSize + kCArgsSlotsSize;
(index - 5) * kPointerSize + StandardFrameConstants::kCArgsSlotsSize;
return MemOperand(sp, offset); return MemOperand(sp, offset);
} }

2
deps/v8/src/mips/regexp-macro-assembler-mips.cc

@ -1050,7 +1050,7 @@ int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
MaybeObject* result = Execution::HandleStackGuardInterrupt(); MaybeObject* result = Execution::HandleStackGuardInterrupt();
if (*code_handle != re_code) { // Return address no longer valid. if (*code_handle != re_code) { // Return address no longer valid.
int delta = *code_handle - re_code; int delta = code_handle->address() - re_code->address();
// Overwrite the return address on the stack. // Overwrite the return address on the stack.
*return_address += delta; *return_address += delta;
} }

17
deps/v8/src/mips/simulator-mips.cc

@ -1409,20 +1409,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
int32_t arg1 = get_register(a1); int32_t arg1 = get_register(a1);
int32_t arg2 = get_register(a2); int32_t arg2 = get_register(a2);
int32_t arg3 = get_register(a3); int32_t arg3 = get_register(a3);
int32_t arg4 = 0;
int32_t arg5 = 0;
// Need to check if sp is valid before assigning arg4, arg5.
// This is a fix for cctest test-api/CatchStackOverflow which causes
// the stack to overflow. For some reason arm doesn't need this
// stack check here.
int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
int32_t* stack = reinterpret_cast<int32_t*>(stack_); // Args 4 and 5 are on the stack after the reserved space for args 0..3.
if (stack_pointer >= stack && stack_pointer < stack + stack_size_ - 5) { int32_t arg4 = stack_pointer[4];
// Args 4 and 5 are on the stack after the reserved space for args 0..3. int32_t arg5 = stack_pointer[5];
arg4 = stack_pointer[4];
arg5 = stack_pointer[5];
}
bool fp_call = bool fp_call =
(redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) || (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
@ -2725,7 +2716,7 @@ int32_t Simulator::Call(byte* entry, int argument_count, ...) {
// Store remaining arguments on stack, from low to high memory. // Store remaining arguments on stack, from low to high memory.
intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
for (int i = 4; i < argument_count; i++) { 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); va_end(parameters);
set_register(sp, entry_stack); set_register(sp, entry_stack);

6
deps/v8/src/mips/stub-cache-mips.cc

@ -3501,7 +3501,7 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
// We are not untagging smi key and instead work with it // We are not untagging smi key and instead work with it
// as if it was premultiplied by 2. // as if it was premultiplied by 2.
ASSERT((kSmiTag == 0) && (kSmiTagSize == 1)); STATIC_ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
Register value = a2; Register value = a2;
switch (elements_kind) { switch (elements_kind) {
@ -4213,7 +4213,7 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
// Load the result and make sure it's not the hole. // Load the result and make sure it's not the hole.
__ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ Addu(a3, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize); __ sll(t0, a0, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t0, t0, a3); __ Addu(t0, t0, a3);
__ lw(t0, MemOperand(t0)); __ lw(t0, MemOperand(t0));
@ -4344,7 +4344,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
__ Addu(scratch, __ Addu(scratch,
elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
__ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize); __ sll(scratch2, key_reg, kPointerSizeLog2 - kSmiTagSize);
__ Addu(scratch3, scratch2, scratch); __ Addu(scratch3, scratch2, scratch);
__ sw(value_reg, MemOperand(scratch3)); __ sw(value_reg, MemOperand(scratch3));

12
deps/v8/src/mksnapshot.cc

@ -29,8 +29,6 @@
#include <bzlib.h> #include <bzlib.h>
#endif #endif
#include <signal.h> #include <signal.h>
#include <string>
#include <map>
#include "v8.h" #include "v8.h"
@ -86,16 +84,6 @@ class CounterCollection {
}; };
// 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 { class Compressor {
public: public:
virtual ~Compressor() {} virtual ~Compressor() {}

16
deps/v8/src/objects-inl.h

@ -171,7 +171,7 @@ bool Object::IsSymbol() {
// Because the symbol tag is non-zero and no non-string types have the // Because the symbol tag is non-zero and no non-string types have the
// symbol bit set we can test for symbols with a very simple test // symbol bit set we can test for symbols with a very simple test
// operation. // operation.
ASSERT(kSymbolTag != 0); STATIC_ASSERT(kSymbolTag != 0);
ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE);
return (type & kIsSymbolMask) != 0; return (type & kIsSymbolMask) != 0;
} }
@ -256,7 +256,7 @@ StringShape::StringShape(InstanceType t)
bool StringShape::IsSymbol() { bool StringShape::IsSymbol() {
ASSERT(valid()); ASSERT(valid());
ASSERT(kSymbolTag != 0); STATIC_ASSERT(kSymbolTag != 0);
return (type_ & kIsSymbolMask) != 0; return (type_ & kIsSymbolMask) != 0;
} }
@ -1749,9 +1749,15 @@ bool FixedDoubleArray::is_the_hole(int index) {
void FixedDoubleArray::Initialize(FixedDoubleArray* from) { void FixedDoubleArray::Initialize(FixedDoubleArray* from) {
int old_length = from->length(); int old_length = from->length();
ASSERT(old_length < length()); ASSERT(old_length < length());
OS::MemCopy(FIELD_ADDR(this, kHeaderSize), if (old_length * kDoubleSize >= OS::kMinComplexMemCopy) {
FIELD_ADDR(from, kHeaderSize), OS::MemCopy(FIELD_ADDR(this, kHeaderSize),
old_length * kDoubleSize); FIELD_ADDR(from, kHeaderSize),
old_length * kDoubleSize);
} else {
for (int i = 0; i < old_length; ++i) {
set(i, from->get_scalar(i));
}
}
int offset = kHeaderSize + old_length * kDoubleSize; int offset = kHeaderSize + old_length * kDoubleSize;
for (int current = from->length(); current < length(); ++current) { for (int current = from->length(); current < length(); ++current) {
WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double()); WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double());

2
deps/v8/src/objects.cc

@ -7009,7 +7009,7 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
JSFunction* function = JSFunction* function =
JSFunction::cast(LiteralArray()->get(function_id)); JSFunction::cast(LiteralArray()->get(function_id));
unsigned height = iterator.Next(); unsigned height = iterator.Next();
PrintF(out, "{ast_id=%d, \nfunction=", ast_id); PrintF(out, "{ast_id=%d, function=", ast_id);
function->PrintName(out); function->PrintName(out);
PrintF(out, ", height=%u}", height); PrintF(out, ", height=%u}", height);
break; break;

5
deps/v8/src/objects.h

@ -496,6 +496,11 @@ STATIC_ASSERT(
STATIC_ASSERT( STATIC_ASSERT(
(kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag); (kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag);
// Use this mask to distinguish between cons and slice only after making
// sure that the string is one of the two (an indirect string).
const uint32_t kSlicedNotConsMask = kSlicedStringTag & ~kConsStringTag;
STATIC_ASSERT(IS_POWER_OF_TWO(kSlicedNotConsMask) && kSlicedNotConsMask != 0);
// If bit 7 is clear, then bit 3 indicates whether this two-byte // If bit 7 is clear, then bit 3 indicates whether this two-byte
// string actually contains ascii data. // string actually contains ascii data.
const uint32_t kAsciiDataHintMask = 0x08; const uint32_t kAsciiDataHintMask = 0x08;

120
deps/v8/src/parser.cc

@ -30,6 +30,7 @@
#include "api.h" #include "api.h"
#include "ast-inl.h" #include "ast-inl.h"
#include "bootstrapper.h" #include "bootstrapper.h"
#include "char-predicates-inl.h"
#include "codegen.h" #include "codegen.h"
#include "compiler.h" #include "compiler.h"
#include "func-name-inferrer.h" #include "func-name-inferrer.h"
@ -532,7 +533,7 @@ LexicalScope::LexicalScope(Parser* parser, Scope* scope, Isolate* isolate)
parser->top_scope_ = scope; parser->top_scope_ = scope;
parser->lexical_scope_ = this; parser->lexical_scope_ = this;
parser->with_nesting_level_ = 0; parser->with_nesting_level_ = 0;
isolate->set_ast_node_id(AstNode::kFunctionEntryId + 1); isolate->set_ast_node_id(AstNode::kDeclarationsId + 1);
} }
@ -647,6 +648,11 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
if (ok && top_scope_->is_strict_mode()) { if (ok && top_scope_->is_strict_mode()) {
CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok); CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
} }
if (ok && harmony_block_scoping_) {
CheckConflictingVarDeclarations(scope, &ok);
}
if (ok) { if (ok) {
result = new(zone()) FunctionLiteral( result = new(zone()) FunctionLiteral(
isolate(), isolate(),
@ -1343,14 +1349,32 @@ VariableProxy* Parser::Declare(Handle<String> name,
// Declare the name. // Declare the name.
var = declaration_scope->DeclareLocal(name, mode); var = declaration_scope->DeclareLocal(name, mode);
} else { } else {
// The name was declared before; check for conflicting re-declarations. // The name was declared in this scope before; check for conflicting
// We have a conflict if either of the declarations is not a var. There // re-declarations. We have a conflict if either of the declarations is
// is similar code in runtime.cc in the Declare functions. // 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)) { if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) {
// We only have vars, consts and lets in declarations. // We only have vars, consts and lets in declarations.
ASSERT(var->mode() == Variable::VAR || ASSERT(var->mode() == Variable::VAR ||
var->mode() == Variable::CONST || var->mode() == Variable::CONST ||
var->mode() == Variable::LET); 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.
SmartPointer<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" : const char* type = (var->mode() == Variable::VAR) ? "var" :
(var->mode() == Variable::CONST) ? "const" : "let"; (var->mode() == Variable::CONST) ? "const" : "let";
Handle<String> type_string = Handle<String> type_string =
@ -1379,8 +1403,10 @@ VariableProxy* Parser::Declare(Handle<String> name,
// semantic issue as long as we keep the source order, but it may be // semantic issue as long as we keep the source order, but it may be
// a performance issue since it may lead to repeated // a performance issue since it may lead to repeated
// Runtime::DeclareContextSlot() calls. // Runtime::DeclareContextSlot() calls.
VariableProxy* proxy = declaration_scope->NewUnresolved(name, false); VariableProxy* proxy = declaration_scope->NewUnresolved(
declaration_scope->AddDeclaration(new(zone()) Declaration(proxy, mode, fun)); 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. // For global const variables we bind the proxy to a variable.
if (mode == Variable::CONST && declaration_scope->is_global_scope()) { if (mode == Variable::CONST && declaration_scope->is_global_scope()) {
@ -1534,9 +1560,6 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
Scope* block_scope = NewScope(top_scope_, Scope* block_scope = NewScope(top_scope_,
Scope::BLOCK_SCOPE, Scope::BLOCK_SCOPE,
inside_with()); inside_with());
body->set_block_scope(block_scope);
block_scope->DeclareLocal(isolate()->factory()->block_scope_symbol(),
Variable::VAR);
if (top_scope_->is_strict_mode()) { if (top_scope_->is_strict_mode()) {
block_scope->EnableStrictMode(); block_scope->EnableStrictMode();
} }
@ -1559,21 +1582,11 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
} }
} }
Expect(Token::RBRACE, CHECK_OK); 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; top_scope_ = saved_scope;
// Create a result block. block_scope = block_scope->FinalizeBlockScope();
Block* result = new(zone()) Block(isolate(), NULL, 1, false); body->set_block_scope(block_scope);
result->AddStatement(try_finally); return body;
return result;
} }
@ -1609,7 +1622,13 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
Variable::Mode mode = Variable::VAR; Variable::Mode mode = Variable::VAR;
// True if the binding needs initialization. 'let' and 'const' declared
// bindings are created uninitialized by their declaration nodes and
// need initialization. 'var' declared bindings are always initialized
// immediately by their declaration nodes.
bool needs_init = false;
bool is_const = false; bool is_const = false;
Token::Value init_op = Token::INIT_VAR;
if (peek() == Token::VAR) { if (peek() == Token::VAR) {
Consume(Token::VAR); Consume(Token::VAR);
} else if (peek() == Token::CONST) { } else if (peek() == Token::CONST) {
@ -1621,6 +1640,8 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
} }
mode = Variable::CONST; mode = Variable::CONST;
is_const = true; is_const = true;
needs_init = true;
init_op = Token::INIT_CONST;
} else if (peek() == Token::LET) { } else if (peek() == Token::LET) {
Consume(Token::LET); Consume(Token::LET);
if (var_context != kSourceElement && if (var_context != kSourceElement &&
@ -1631,6 +1652,8 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
return NULL; return NULL;
} }
mode = Variable::LET; mode = Variable::LET;
needs_init = true;
init_op = Token::INIT_LET;
} else { } else {
UNREACHABLE(); // by current callers UNREACHABLE(); // by current callers
} }
@ -1732,9 +1755,8 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
} }
} }
// Make sure that 'const c' actually initializes 'c' to undefined // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
// even though it seems like a stupid thing to do. if (value == NULL && needs_init) {
if (value == NULL && is_const) {
value = GetLiteralUndefined(); value = GetLiteralUndefined();
} }
@ -1811,23 +1833,25 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
block->AddStatement(new(zone()) ExpressionStatement(initialize)); block->AddStatement(new(zone()) ExpressionStatement(initialize));
} }
// Add an assignment node to the initialization statement block if // Add an assignment node to the initialization statement block if we still
// we still have a pending initialization value. We must distinguish // have a pending initialization value. We must distinguish between
// between variables and constants: Variable initializations are simply // different kinds of declarations: 'var' initializations are simply
// assignments (with all the consequences if they are inside a 'with' // assignments (with all the consequences if they are inside a 'with'
// statement - they may change a 'with' object property). Constant // statement - they may change a 'with' object property). Constant
// initializations always assign to the declared constant which is // initializations always assign to the declared constant which is
// always at the function scope level. This is only relevant for // always at the function scope level. This is only relevant for
// dynamically looked-up variables and constants (the start context // dynamically looked-up variables and constants (the start context
// for constant lookups is always the function context, while it is // 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) { if (value != NULL) {
Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR); bool in_with = mode == Variable::VAR ? inside_with() : false;
bool in_with = is_const ? false : inside_with();
VariableProxy* proxy = VariableProxy* proxy =
initialization_scope->NewUnresolved(name, in_with); initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment = Assignment* assignment =
new(zone()) Assignment(isolate(), op, proxy, value, position); new(zone()) Assignment(isolate(), init_op, proxy, value, position);
if (block) { if (block) {
block->AddStatement(new(zone()) ExpressionStatement(assignment)); block->AddStatement(new(zone()) ExpressionStatement(assignment));
} }
@ -2199,7 +2223,9 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
if (top_scope_->is_strict_mode()) { if (top_scope_->is_strict_mode()) {
catch_scope->EnableStrictMode(); catch_scope->EnableStrictMode();
} }
catch_variable = catch_scope->DeclareLocal(name, Variable::VAR); Variable::Mode mode = harmony_block_scoping_
? Variable::LET : Variable::VAR;
catch_variable = catch_scope->DeclareLocal(name, mode);
catch_block = new(zone()) Block(isolate(), NULL, 2, false); catch_block = new(zone()) Block(isolate(), NULL, 2, false);
Scope* saved_scope = top_scope_; Scope* saved_scope = top_scope_;
@ -3728,7 +3754,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
reserved_loc = scanner().location(); reserved_loc = scanner().location();
} }
top_scope_->DeclareParameter(param_name); top_scope_->DeclareParameter(param_name,
harmony_block_scoping_
? Variable::LET
: Variable::VAR);
num_parameters++; num_parameters++;
if (num_parameters > kMaxNumFunctionParameters) { if (num_parameters > kMaxNumFunctionParameters) {
ReportMessageAt(scanner().location(), "too_many_parameters", ReportMessageAt(scanner().location(), "too_many_parameters",
@ -3855,6 +3884,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
} }
} }
if (harmony_block_scoping_) {
CheckConflictingVarDeclarations(scope, CHECK_OK);
}
FunctionLiteral* function_literal = FunctionLiteral* function_literal =
new(zone()) FunctionLiteral(isolate(), new(zone()) FunctionLiteral(isolate(),
function_name, function_name,
@ -4061,6 +4094,25 @@ void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
} }
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();
SmartPointer<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 // This function reads an identifier name and determines whether or not it
// is 'get' or 'set'. // is 'get' or 'set'.
Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get, Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,

11
deps/v8/src/parser.h

@ -645,6 +645,17 @@ class Parser {
// Strict mode octal literal validation. // Strict mode octal literal validation.
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); 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 // Parser support
VariableProxy* Declare(Handle<String> name, Variable::Mode mode, VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
FunctionLiteral* fun, FunctionLiteral* fun,

6
deps/v8/src/platform-linux.cc

@ -130,13 +130,7 @@ void OS::Setup() {
uint64_t OS::CpuFeaturesImpliedByPlatform() { 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. return 0; // Linux runs on anything.
#endif
} }

98
deps/v8/src/prettyprinter.cc

@ -284,28 +284,6 @@ void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
} }
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) { void PrettyPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteral(node->name(), false); PrintLiteral(node->name(), false);
} }
@ -751,7 +729,7 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
if (node->fun() == NULL) { if (node->fun() == NULL) {
// var or const declarations // var or const declarations
PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()), PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
node->proxy()->AsVariable(), node->proxy()->var(),
node->proxy()->name()); node->proxy()->name());
} else { } else {
// function declarations // function declarations
@ -959,19 +937,26 @@ void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
} }
void AstPrinter::VisitSlot(Slot* node) {
PrintIndented("SLOT ");
PrettyPrinter::VisitSlot(node);
Print("\n");
}
void AstPrinter::VisitVariableProxy(VariableProxy* node) { void AstPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name());
Variable* var = node->var(); Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) { PrintLiteralWithModeIndented("VAR PROXY", var, node->name());
IndentedScope indent(this); { IndentedScope indent(this);
Visit(var->rewrite()); switch (var->location()) {
case Variable::UNALLOCATED:
break;
case Variable::PARAMETER:
Print("parameter[%d]", var->index());
break;
case Variable::LOCAL:
Print("local[%d]", var->index());
break;
case Variable::CONTEXT:
Print("context[%d]", var->index());
break;
case Variable::LOOKUP:
Print("lookup");
break;
}
} }
} }
@ -1287,39 +1272,32 @@ void JsonAstBuilder::VisitConditional(Conditional* expr) {
} }
void JsonAstBuilder::VisitSlot(Slot* expr) { void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
TagScope tag(this, "Slot"); TagScope tag(this, "Variable");
{ {
AttributesScope attributes(this); AttributesScope attributes(this);
switch (expr->type()) { Variable* var = expr->var();
case Slot::PARAMETER: AddAttribute("name", var->name());
AddAttribute("type", "PARAMETER"); switch (var->location()) {
case Variable::UNALLOCATED:
AddAttribute("location", "UNALLOCATED");
break; break;
case Slot::LOCAL: case Variable::PARAMETER:
AddAttribute("type", "LOCAL"); AddAttribute("location", "PARAMETER");
AddAttribute("index", var->index());
break; break;
case Slot::CONTEXT: case Variable::LOCAL:
AddAttribute("type", "CONTEXT"); AddAttribute("location", "LOCAL");
AddAttribute("index", var->index());
break; break;
case Slot::LOOKUP: case Variable::CONTEXT:
AddAttribute("type", "LOOKUP"); AddAttribute("location", "CONTEXT");
AddAttribute("index", var->index());
break;
case Variable::LOOKUP:
AddAttribute("location", "LOOKUP");
break; 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());
} }
} }

3
deps/v8/src/prettyprinter.h

@ -52,7 +52,6 @@ class PrettyPrinter: public AstVisitor {
// Print a node to stdout. // Print a node to stdout.
static void PrintOut(AstNode* node); static void PrintOut(AstNode* node);
virtual void VisitSlot(Slot* node);
// Individual nodes // Individual nodes
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT) AST_NODE_LIST(DECLARE_VISIT)
@ -87,7 +86,6 @@ class AstPrinter: public PrettyPrinter {
const char* PrintProgram(FunctionLiteral* program); const char* PrintProgram(FunctionLiteral* program);
// Individual nodes // Individual nodes
virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT) AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT #undef DECLARE_VISIT
@ -163,7 +161,6 @@ class JsonAstBuilder: public PrettyPrinter {
void AddAttribute(const char* name, bool value); void AddAttribute(const char* name, bool value);
// AST node visit functions. // AST node visit functions.
virtual void VisitSlot(Slot* node);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT) AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT #undef DECLARE_VISIT

34
deps/v8/src/profile-generator.cc

@ -1195,12 +1195,9 @@ void HeapSnapshot::AllocateEntries(int entries_count,
int children_count, int children_count,
int retainers_count) { int retainers_count) {
ASSERT(raw_entries_ == NULL); ASSERT(raw_entries_ == NULL);
raw_entries_ = NewArray<char>(
HeapEntry::EntriesSize(entries_count, children_count, retainers_count));
#ifdef DEBUG
raw_entries_size_ = raw_entries_size_ =
HeapEntry::EntriesSize(entries_count, children_count, retainers_count); HeapEntry::EntriesSize(entries_count, children_count, retainers_count);
#endif raw_entries_ = NewArray<char>(raw_entries_size_);
} }
@ -2984,10 +2981,19 @@ class OutputStreamWriter {
bool aborted_; bool aborted_;
}; };
const int HeapSnapshotJSONSerializer::kMaxSerializableSnapshotRawSize =
256 * MB;
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
ASSERT(writer_ == NULL); ASSERT(writer_ == NULL);
writer_ = new OutputStreamWriter(stream); writer_ = new OutputStreamWriter(stream);
HeapSnapshot* original_snapshot = NULL;
if (snapshot_->raw_entries_size() >= kMaxSerializableSnapshotRawSize) {
// The snapshot is too big. Serialize a fake snapshot.
original_snapshot = snapshot_;
snapshot_ = CreateFakeSnapshot();
}
// Since nodes graph is cyclic, we need the first pass to enumerate // Since nodes graph is cyclic, we need the first pass to enumerate
// them. Strings can be serialized in one pass. // them. Strings can be serialized in one pass.
EnumerateNodes(); EnumerateNodes();
@ -2995,6 +3001,26 @@ void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
delete writer_; delete writer_;
writer_ = NULL; writer_ = NULL;
if (original_snapshot != NULL) {
delete snapshot_;
snapshot_ = original_snapshot;
}
}
HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() {
HeapSnapshot* result = new HeapSnapshot(snapshot_->collection(),
HeapSnapshot::kFull,
snapshot_->title(),
snapshot_->uid());
result->AllocateEntries(2, 1, 0);
HeapEntry* root = result->AddRootEntry(1);
HeapEntry* message = result->AddEntry(
HeapEntry::kString, "The snapshot is too big", 0, 4, 0, 0);
root->SetUnidirElementReference(0, 1, message);
result->SetDominatorsToSelf();
return result;
} }

6
deps/v8/src/profile-generator.h

@ -654,6 +654,7 @@ class HeapSnapshot {
HeapEntry* gc_roots() { return gc_roots_entry_; } HeapEntry* gc_roots() { return gc_roots_entry_; }
HeapEntry* natives_root() { return natives_root_entry_; } HeapEntry* natives_root() { return natives_root_entry_; }
List<HeapEntry*>* entries() { return &entries_; } List<HeapEntry*>* entries() { return &entries_; }
int raw_entries_size() { return raw_entries_size_; }
void AllocateEntries( void AllocateEntries(
int entries_count, int children_count, int retainers_count); int entries_count, int children_count, int retainers_count);
@ -689,9 +690,7 @@ class HeapSnapshot {
char* raw_entries_; char* raw_entries_;
List<HeapEntry*> entries_; List<HeapEntry*> entries_;
bool entries_sorted_; bool entries_sorted_;
#ifdef DEBUG
int raw_entries_size_; int raw_entries_size_;
#endif
friend class HeapSnapshotTester; friend class HeapSnapshotTester;
@ -1097,6 +1096,7 @@ class HeapSnapshotJSONSerializer {
} }
void EnumerateNodes(); void EnumerateNodes();
HeapSnapshot* CreateFakeSnapshot();
int GetNodeId(HeapEntry* entry); int GetNodeId(HeapEntry* entry);
int GetStringId(const char* s); int GetStringId(const char* s);
void SerializeEdge(HeapGraphEdge* edge); void SerializeEdge(HeapGraphEdge* edge);
@ -1108,6 +1108,8 @@ class HeapSnapshotJSONSerializer {
void SerializeStrings(); void SerializeStrings();
void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries); void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
static const int kMaxSerializableSnapshotRawSize;
HeapSnapshot* snapshot_; HeapSnapshot* snapshot_;
HashMap nodes_; HashMap nodes_;
HashMap strings_; HashMap strings_;

6
deps/v8/src/regexp.js

@ -405,7 +405,8 @@ var lastMatchInfoOverride = null;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupRegExp() { function SetUpRegExp() {
%CheckIsBootstrapping();
%FunctionSetInstanceClassName($RegExp, 'RegExp'); %FunctionSetInstanceClassName($RegExp, 'RegExp');
%FunctionSetPrototype($RegExp, new $Object()); %FunctionSetPrototype($RegExp, new $Object());
%SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM); %SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
@ -484,5 +485,4 @@ function SetupRegExp() {
} }
} }
SetUpRegExp();
SetupRegExp();

6
deps/v8/src/runtime-profiler.cc

@ -115,10 +115,8 @@ void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
} }
SharedFunctionInfo* shared = function->shared(); SharedFunctionInfo* shared = function->shared();
// If the code is not optimizable or references context slots, don't try OSR. // If the code is not optimizable, don't try OSR.
if (!shared->code()->optimizable() || !shared->allows_lazy_compilation()) { if (!shared->code()->optimizable()) return;
return;
}
// We are not prepared to do OSR for a function that already has an // We are not prepared to do OSR for a function that already has an
// allocated arguments object. The optimized code would bypass it for // allocated arguments object. The optimized code would bypass it for

125
deps/v8/src/runtime.cc

@ -32,6 +32,7 @@
#include "accessors.h" #include "accessors.h"
#include "api.h" #include "api.h"
#include "arguments.h" #include "arguments.h"
#include "bootstrapper.h"
#include "codegen.h" #include "codegen.h"
#include "compilation-cache.h" #include "compilation-cache.h"
#include "compiler.h" #include "compiler.h"
@ -1149,22 +1150,14 @@ static Failure* ThrowRedeclarationError(Isolate* isolate,
RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ASSERT(args.length() == 4); ASSERT(args.length() == 3);
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<GlobalObject> global = Handle<GlobalObject>( Handle<GlobalObject> global = Handle<GlobalObject>(
isolate->context()->global()); isolate->context()->global());
Handle<Context> context = args.at<Context>(0); Handle<Context> context = args.at<Context>(0);
CONVERT_ARG_CHECKED(FixedArray, pairs, 1); CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
bool is_eval = args.smi_at(2) == 1; CONVERT_SMI_ARG_CHECKED(flags, 2);
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;
// Traverse the name/value pairs and set the properties. // Traverse the name/value pairs and set the properties.
int length = pairs->length(); int length = pairs->length();
@ -1177,7 +1170,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
// assign to it when evaluating the assignment for "const x = // assign to it when evaluating the assignment for "const x =
// <expr>" the initial value is the hole. // <expr>" the initial value is the hole.
bool is_const_property = value->IsTheHole(); bool is_const_property = value->IsTheHole();
bool is_function_declaration = false;
if (value->IsUndefined() || is_const_property) { if (value->IsUndefined() || is_const_property) {
// Lookup the property in the global object, and don't set the // Lookup the property in the global object, and don't set the
// value of the variable if the property is already there. // value of the variable if the property is already there.
@ -1226,6 +1219,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
} }
} }
} else { } else {
is_function_declaration = true;
// Copy the function and update its context. Use it as value. // Copy the function and update its context. Use it as value.
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(value); Handle<SharedFunctionInfo>::cast(value);
@ -1239,10 +1233,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
LookupResult lookup; LookupResult lookup;
global->LocalLookup(*name, &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 // There's a local property that we need to overwrite because
// we're either declaring a function or there's an interceptor // we're either declaring a function or there's an interceptor
// that claims the property is absent. // that claims the property is absent.
@ -1257,6 +1247,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
return ThrowRedeclarationError(isolate, type, name); 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 // Safari does not allow the invocation of callback setters for
// function declarations. To mimic this behavior, we do not allow // function declarations. To mimic this behavior, we do not allow
// the invocation of setters for function values. This makes a // the invocation of setters for function values. This makes a
@ -1267,20 +1270,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
if (value->IsJSFunction()) { if (value->IsJSFunction()) {
// Do not change DONT_DELETE to false from true. // Do not change DONT_DELETE to false from true.
if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) { if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
attributes = static_cast<PropertyAttributes>( attr |= lookup.GetAttributes() & DONT_DELETE;
attributes | (lookup.GetAttributes() & DONT_DELETE));
} }
PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
RETURN_IF_EMPTY_HANDLE(isolate, RETURN_IF_EMPTY_HANDLE(isolate,
SetLocalPropertyIgnoreAttributes(global, SetLocalPropertyIgnoreAttributes(global,
name, name,
value, value,
attributes)); attributes));
} else { } else {
StrictModeFlag strict_mode =
((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
: kNonStrictMode;
RETURN_IF_EMPTY_HANDLE(isolate, RETURN_IF_EMPTY_HANDLE(isolate,
SetProperty(global, SetProperty(global,
name, name,
value, value,
attributes, static_cast<PropertyAttributes>(attr),
strict_mode)); strict_mode));
} }
} }
@ -1306,8 +1313,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
int index; int index;
PropertyAttributes attributes; PropertyAttributes attributes;
ContextLookupFlags flags = DONT_FOLLOW_CHAINS; ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
BindingFlags binding_flags;
Handle<Object> holder = Handle<Object> holder =
context->Lookup(name, flags, &index, &attributes); context->Lookup(name, flags, &index, &attributes, &binding_flags);
if (attributes != ABSENT) { if (attributes != ABSENT) {
// The name was declared before; check for conflicting // The name was declared before; check for conflicting
@ -1594,8 +1602,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
int index; int index;
PropertyAttributes attributes; PropertyAttributes attributes;
ContextLookupFlags flags = FOLLOW_CHAINS; ContextLookupFlags flags = FOLLOW_CHAINS;
BindingFlags binding_flags;
Handle<Object> holder = Handle<Object> holder =
context->Lookup(name, flags, &index, &attributes); context->Lookup(name, flags, &index, &attributes, &binding_flags);
// In most situations, the property introduced by the const // In most situations, the property introduced by the const
// declaration should be present in the context extension object. // declaration should be present in the context extension object.
@ -2145,6 +2154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
@ -5974,6 +5984,19 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
int pattern_length = pattern->length(); int pattern_length = pattern->length();
RUNTIME_ASSERT(pattern_length > 0); 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 // The limit can be very large (0xffffffffu), but since the pattern
// isn't empty, we can never create more parts than ~half the length // isn't empty, we can never create more parts than ~half the length
// of the subject. // of the subject.
@ -6067,6 +6090,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
part_start = part_end + pattern_length; part_start = part_end + pattern_length;
} }
if (limit == 0xffffffffu) {
StringSplitCache::Enter(isolate->heap(),
isolate->heap()->string_split_cache(),
*subject,
*pattern,
*elements);
}
return *result; return *result;
} }
@ -8248,6 +8279,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
} }
RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) { RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
@ -8386,7 +8423,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
int index; int index;
PropertyAttributes attributes; PropertyAttributes attributes;
ContextLookupFlags flags = FOLLOW_CHAINS; ContextLookupFlags flags = FOLLOW_CHAINS;
Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); BindingFlags binding_flags;
Handle<Object> holder = context->Lookup(name,
flags,
&index,
&attributes,
&binding_flags);
// If the slot was not found the result is true. // If the slot was not found the result is true.
if (holder.is_null()) { if (holder.is_null()) {
@ -8488,7 +8530,12 @@ static ObjectPair LoadContextSlotHelper(Arguments args,
int index; int index;
PropertyAttributes attributes; PropertyAttributes attributes;
ContextLookupFlags flags = FOLLOW_CHAINS; ContextLookupFlags flags = FOLLOW_CHAINS;
Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); BindingFlags binding_flags;
Handle<Object> holder = context->Lookup(name,
flags,
&index,
&attributes,
&binding_flags);
// If the index is non-negative, the slot has been found in a local // If the index is non-negative, the slot has been found in a local
// variable or a parameter. Read it from the context object or the // variable or a parameter. Read it from the context object or the
@ -8504,7 +8551,17 @@ static ObjectPair LoadContextSlotHelper(Arguments args,
MaybeObject* value = (holder->IsContext()) MaybeObject* value = (holder->IsContext())
? Context::cast(*holder)->get(index) ? Context::cast(*holder)->get(index)
: JSObject::cast(*holder)->GetElement(index); : JSObject::cast(*holder)->GetElement(index);
return MakePair(Unhole(isolate->heap(), value, attributes), *receiver); // Check for uninitialized bindings.
if (holder->IsContext() &&
binding_flags == MUTABLE_CHECK_INITIALIZED &&
value->IsTheHole()) {
Handle<Object> reference_error =
isolate->factory()->NewReferenceError("not_defined",
HandleVector(&name, 1));
return MakePair(isolate->Throw(*reference_error), NULL);
} else {
return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
}
} }
// If the holder is found, we read the property from it. // If the holder is found, we read the property from it.
@ -8570,14 +8627,27 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
int index; int index;
PropertyAttributes attributes; PropertyAttributes attributes;
ContextLookupFlags flags = FOLLOW_CHAINS; ContextLookupFlags flags = FOLLOW_CHAINS;
Handle<Object> holder = context->Lookup(name, flags, &index, &attributes); BindingFlags binding_flags;
Handle<Object> holder = context->Lookup(name,
flags,
&index,
&attributes,
&binding_flags);
if (index >= 0) { if (index >= 0) {
if (holder->IsContext()) { if (holder->IsContext()) {
Handle<Context> context = Handle<Context>::cast(holder);
if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
context->get(index)->IsTheHole()) {
Handle<Object> error =
isolate->factory()->NewReferenceError("not_defined",
HandleVector(&name, 1));
return isolate->Throw(*error);
}
// Ignore if read_only variable. // Ignore if read_only variable.
if ((attributes & READ_ONLY) == 0) { if ((attributes & READ_ONLY) == 0) {
// Context is a fixed array and set cannot fail. // Context is a fixed array and set cannot fail.
Context::cast(*holder)->set(index, *value); context->set(index, *value);
} else if (strict_mode == kStrictMode) { } else if (strict_mode == kStrictMode) {
// Setting read only property in strict mode. // Setting read only property in strict mode.
Handle<Object> error = Handle<Object> error =
@ -9029,10 +9099,13 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
// it is bound in the global context. // it is bound in the global context.
int index = -1; int index = -1;
PropertyAttributes attributes = ABSENT; PropertyAttributes attributes = ABSENT;
BindingFlags binding_flags;
while (true) { while (true) {
receiver = context->Lookup(isolate->factory()->eval_symbol(), receiver = context->Lookup(isolate->factory()->eval_symbol(),
FOLLOW_PROTOTYPE_CHAIN, FOLLOW_PROTOTYPE_CHAIN,
&index, &attributes); &index,
&attributes,
&binding_flags);
// Stop search when eval is found or when the global context is // Stop search when eval is found or when the global context is
// reached. // reached.
if (attributes != ABSENT || context->IsGlobalContext()) break; if (attributes != ABSENT || context->IsGlobalContext()) break;

13
deps/v8/src/runtime.h

@ -79,6 +79,7 @@ namespace internal {
F(PreventExtensions, 1, 1)\ F(PreventExtensions, 1, 1)\
\ \
/* Utilities */ \ /* Utilities */ \
F(CheckIsBootstrapping, 0, 1) \
F(GetFunctionDelegate, 1, 1) \ F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \ F(GetConstructorDelegate, 1, 1) \
F(NewArgumentsFast, 3, 1) \ F(NewArgumentsFast, 3, 1) \
@ -317,7 +318,7 @@ namespace internal {
F(StoreContextSlot, 4, 1) \ F(StoreContextSlot, 4, 1) \
\ \
/* Declarations and initialization */ \ /* Declarations and initialization */ \
F(DeclareGlobals, 4, 1) \ F(DeclareGlobals, 3, 1) \
F(DeclareContextSlot, 4, 1) \ F(DeclareContextSlot, 4, 1) \
F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \ F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \
F(InitializeConstGlobal, 2, 1) \ F(InitializeConstGlobal, 2, 1) \
@ -663,6 +664,16 @@ class Runtime : public AllStatic {
static void PerformGC(Object* result); 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 } } // namespace v8::internal
#endif // V8_RUNTIME_H_ #endif // V8_RUNTIME_H_

1
deps/v8/src/runtime.js

@ -48,6 +48,7 @@ const $Number = global.Number;
const $Function = global.Function; const $Function = global.Function;
const $Boolean = global.Boolean; const $Boolean = global.Boolean;
const $NaN = 0/0; const $NaN = 0/0;
const builtins = this;
// ECMA-262 Section 11.9.3. // ECMA-262 Section 11.9.3.
function EQUALS(y) { function EQUALS(y) {

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

@ -362,7 +362,7 @@ class Scanner {
// Call this after setting source_ to the input. // Call this after setting source_ to the input.
void Init() { void Init() {
// Set c0_ (one character ahead) // Set c0_ (one character ahead)
ASSERT(kCharacterLookaheadBufferSize == 1); STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
Advance(); Advance();
// Initialize current_ to not refer to a literal. // Initialize current_ to not refer to a literal.
current_.literal_chars = NULL; current_.literal_chars = NULL;

2
deps/v8/src/scanner.h

@ -28,8 +28,6 @@
#ifndef V8_SCANNER_H_ #ifndef V8_SCANNER_H_
#define V8_SCANNER_H_ #define V8_SCANNER_H_
#include "token.h"
#include "char-predicates-inl.h"
#include "scanner-base.h" #include "scanner-base.h"
namespace v8 { namespace v8 {

65
deps/v8/src/scopeinfo.cc

@ -39,12 +39,8 @@ namespace internal {
static int CompareLocal(Variable* const* v, Variable* const* w) { static int CompareLocal(Variable* const* v, Variable* const* w) {
Slot* s = (*v)->AsSlot(); int x = (*v)->index();
Slot* t = (*w)->AsSlot(); int y = (*w)->index();
// 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);
// Consider sorting them according to type as well? // Consider sorting them according to type as well?
return x - y; return x - y;
} }
@ -86,27 +82,24 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
for (int i = 0; i < locals.length(); i++) { for (int i = 0; i < locals.length(); i++) {
Variable* var = locals[i]; Variable* var = locals[i];
if (var->is_used()) { if (var->is_used()) {
Slot* slot = var->AsSlot(); switch (var->location()) {
if (slot != NULL) { case Variable::UNALLOCATED:
switch (slot->type()) { case Variable::PARAMETER:
case Slot::PARAMETER: break;
// explicitly added to parameters_ above - ignore
break; case Variable::LOCAL:
ASSERT(stack_slots_.length() == var->index());
case Slot::LOCAL: stack_slots_.Add(var->name());
ASSERT(stack_slots_.length() == slot->index()); break;
stack_slots_.Add(var->name());
break; case Variable::CONTEXT:
heap_locals.Add(var);
case Slot::CONTEXT: break;
heap_locals.Add(var);
break; case Variable::LOOKUP:
// We don't expect lookup variables in the locals list.
case Slot::LOOKUP: UNREACHABLE();
// This is currently not used. break;
UNREACHABLE();
break;
}
} }
} }
} }
@ -115,9 +108,9 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
if (scope->num_heap_slots() > 0) { if (scope->num_heap_slots() > 0) {
// Add user-defined slots. // Add user-defined slots.
for (int i = 0; i < heap_locals.length(); i++) { 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()); 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_modes_.length());
context_slots_.Add(heap_locals[i]->name()); context_slots_.Add(heap_locals[i]->name());
context_modes_.Add(heap_locals[i]->mode()); context_modes_.Add(heap_locals[i]->mode());
@ -131,18 +124,18 @@ ScopeInfo<Allocator>::ScopeInfo(Scope* scope)
// For now, this must happen at the very end because of the // For now, this must happen at the very end because of the
// ordering of the scope info slots and the respective slot indices. // ordering of the scope info slots and the respective slot indices.
if (scope->is_function_scope()) { if (scope->is_function_scope()) {
Variable* var = scope->function(); VariableProxy* proxy = scope->function();
if (var != NULL && if (proxy != NULL &&
var->is_used() && proxy->var()->is_used() &&
var->AsSlot()->type() == Slot::CONTEXT) { proxy->var()->IsContextSlot()) {
function_name_ = var->name(); function_name_ = proxy->name();
// Note that we must not find the function name in the context slot // Note that we must not find the function name in the context slot
// list - instead it must be handled separately in the // list - instead it must be handled separately in the
// Contexts::Lookup() function. Thus record an empty symbol here so we // Contexts::Lookup() function. Thus record an empty symbol here so we
// get the correct number of context slots. // 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()); context_slots_.length());
ASSERT(var->AsSlot()->index() - Context::MIN_CONTEXT_SLOTS == ASSERT(proxy->var()->index() - Context::MIN_CONTEXT_SLOTS ==
context_modes_.length()); context_modes_.length());
context_slots_.Add(FACTORY->empty_symbol()); context_slots_.Add(FACTORY->empty_symbol());
context_modes_.Add(Variable::INTERNAL); context_modes_.Add(Variable::INTERNAL);

151
deps/v8/src/scopes.cc

@ -31,7 +31,6 @@
#include "bootstrapper.h" #include "bootstrapper.h"
#include "compiler.h" #include "compiler.h"
#include "prettyprinter.h"
#include "scopeinfo.h" #include "scopeinfo.h"
#include "allocation-inl.h" #include "allocation-inl.h"
@ -314,7 +313,7 @@ void Scope::Initialize(bool inside_with) {
Variable::VAR, Variable::VAR,
false, false,
Variable::THIS); Variable::THIS);
var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1)); var->AllocateTo(Variable::PARAMETER, -1);
receiver_ = var; receiver_ = var;
} }
@ -331,6 +330,35 @@ void Scope::Initialize(bool inside_with) {
} }
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* Scope::LocalLookup(Handle<String> name) {
Variable* result = variables_.Lookup(name); Variable* result = variables_.Lookup(name);
if (result != NULL || scope_info_.is_null()) { if (result != NULL || scope_info_.is_null()) {
@ -360,7 +388,7 @@ Variable* Scope::LocalLookup(Handle<String> name) {
Variable* var = Variable* var =
variables_.Declare(this, name, mode, true, Variable::NORMAL); variables_.Declare(this, name, mode, true, Variable::NORMAL);
var->set_rewrite(NewSlot(var, Slot::CONTEXT, index)); var->AllocateTo(Variable::CONTEXT, index);
return var; return var;
} }
@ -378,16 +406,18 @@ Variable* Scope::Lookup(Handle<String> name) {
Variable* Scope::DeclareFunctionVar(Handle<String> name) { Variable* Scope::DeclareFunctionVar(Handle<String> name) {
ASSERT(is_function_scope() && function_ == NULL); ASSERT(is_function_scope() && function_ == NULL);
function_ = new Variable(this, name, Variable::CONST, true, Variable::NORMAL); Variable* function_var =
return function_; 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(!already_resolved());
ASSERT(is_function_scope()); ASSERT(is_function_scope());
Variable* var = Variable* var =
variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL); variables_.Declare(this, name, mode, true, Variable::NORMAL);
params_.Add(var); params_.Add(var);
} }
@ -407,7 +437,8 @@ Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
Variable* Scope::DeclareGlobal(Handle<String> name) { Variable* Scope::DeclareGlobal(Handle<String> name) {
ASSERT(is_global_scope()); ASSERT(is_global_scope());
return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, true, return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL,
true,
Variable::NORMAL); Variable::NORMAL);
} }
@ -440,8 +471,11 @@ void Scope::RemoveUnresolved(VariableProxy* var) {
Variable* Scope::NewTemporary(Handle<String> name) { Variable* Scope::NewTemporary(Handle<String> name) {
ASSERT(!already_resolved()); ASSERT(!already_resolved());
Variable* var = Variable* var = new Variable(this,
new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL); name,
Variable::TEMPORARY,
true,
Variable::NORMAL);
temps_.Add(var); temps_.Add(var);
return var; return var;
} }
@ -467,6 +501,28 @@ void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
} }
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> template<class Allocator>
void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) { void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
// Collect variables in this scope. // Collect variables in this scope.
@ -612,17 +668,35 @@ static void PrintName(Handle<String> name) {
} }
static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) { static void PrintLocation(Variable* var) {
if (var->is_used() || var->rewrite() != NULL) { 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())); Indent(indent, Variable::Mode2String(var->mode()));
PrintF(" "); PrintF(" ");
PrintName(var->name()); PrintName(var->name());
PrintF("; // "); PrintF("; // ");
if (var->rewrite() != NULL) { PrintLocation(var);
PrintF("%s, ", printer->Print(var->rewrite()));
if (var->is_accessed_from_inner_function_scope()) PrintF(", ");
}
if (var->is_accessed_from_inner_function_scope()) { if (var->is_accessed_from_inner_function_scope()) {
if (!var->IsUnallocated()) PrintF(", ");
PrintF("inner scope access"); PrintF("inner scope access");
} }
PrintF("\n"); PrintF("\n");
@ -630,10 +704,10 @@ static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
} }
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)) { for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
Variable* var = reinterpret_cast<Variable*>(p->value); Variable* var = reinterpret_cast<Variable*>(p->value);
PrintVar(printer, indent, var); PrintVar(indent, var);
} }
} }
@ -690,25 +764,24 @@ void Scope::Print(int n) {
PrintF("%d heap slots\n", num_heap_slots_); } PrintF("%d heap slots\n", num_heap_slots_); }
// Print locals. // Print locals.
PrettyPrinter printer;
Indent(n1, "// function var\n"); Indent(n1, "// function var\n");
if (function_ != NULL) { if (function_ != NULL) {
PrintVar(&printer, n1, function_); PrintVar(n1, function_->var());
} }
Indent(n1, "// temporary vars\n"); Indent(n1, "// temporary vars\n");
for (int i = 0; i < temps_.length(); i++) { for (int i = 0; i < temps_.length(); i++) {
PrintVar(&printer, n1, temps_[i]); PrintVar(n1, temps_[i]);
} }
Indent(n1, "// local vars\n"); Indent(n1, "// local vars\n");
PrintMap(&printer, n1, &variables_); PrintMap(n1, &variables_);
Indent(n1, "// dynamic vars\n"); Indent(n1, "// dynamic vars\n");
if (dynamics_ != NULL) { if (dynamics_ != NULL) {
PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC)); PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC));
PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL)); PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL)); PrintMap(n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
} }
// Print inner scopes (disable by providing negative n). // Print inner scopes (disable by providing negative n).
@ -732,7 +805,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
// Declare a new non-local. // Declare a new non-local.
var = map->Declare(NULL, name, mode, true, Variable::NORMAL); var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
// Allocate it by giving it a dynamic lookup. // Allocate it by giving it a dynamic lookup.
var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1)); var->AllocateTo(Variable::LOOKUP, -1);
} }
return var; return var;
} }
@ -774,7 +847,7 @@ Variable* Scope::LookupRecursive(Handle<String> name,
// the name of named function literal is kept in an intermediate scope // the name of named function literal is kept in an intermediate scope
// in between this scope and the next outer scope.) // in between this scope and the next outer scope.)
if (function_ != NULL && function_->name().is_identical_to(name)) { if (function_ != NULL && function_->name().is_identical_to(name)) {
var = function_; var = function_->var();
} else if (outer_scope_ != NULL) { } else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive( var = outer_scope_->LookupRecursive(
@ -992,12 +1065,12 @@ bool Scope::HasArgumentsParameter() {
void Scope::AllocateStackSlot(Variable* var) { 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) { void Scope::AllocateHeapSlot(Variable* var) {
var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++)); var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
} }
@ -1043,14 +1116,14 @@ void Scope::AllocateParameterLocals() {
if (MustAllocate(var)) { if (MustAllocate(var)) {
if (MustAllocateInContext(var)) { if (MustAllocateInContext(var)) {
ASSERT(var->rewrite() == NULL || var->IsContextSlot()); ASSERT(var->IsUnallocated() || var->IsContextSlot());
if (var->rewrite() == NULL) { if (var->IsUnallocated()) {
AllocateHeapSlot(var); AllocateHeapSlot(var);
} }
} else { } else {
ASSERT(var->rewrite() == NULL || var->IsParameter()); ASSERT(var->IsUnallocated() || var->IsParameter());
if (var->rewrite() == NULL) { if (var->IsUnallocated()) {
var->set_rewrite(NewSlot(var, Slot::PARAMETER, i)); var->AllocateTo(Variable::PARAMETER, i);
} }
} }
} }
@ -1060,11 +1133,9 @@ void Scope::AllocateParameterLocals() {
void Scope::AllocateNonParameterLocal(Variable* var) { void Scope::AllocateNonParameterLocal(Variable* var) {
ASSERT(var->scope() == this); ASSERT(var->scope() == this);
ASSERT(var->rewrite() == NULL || ASSERT(!var->IsVariable(isolate_->factory()->result_symbol()) ||
!var->IsVariable(isolate_->factory()->result_symbol()) || !var->IsStackLocal());
var->AsSlot() == NULL || if (var->IsUnallocated() && MustAllocate(var)) {
var->AsSlot()->type() != Slot::LOCAL);
if (var->rewrite() == NULL && MustAllocate(var)) {
if (MustAllocateInContext(var)) { if (MustAllocateInContext(var)) {
AllocateHeapSlot(var); AllocateHeapSlot(var);
} else { } else {
@ -1092,7 +1163,7 @@ void Scope::AllocateNonParameterLocals() {
// because of the current ScopeInfo implementation (see // because of the current ScopeInfo implementation (see
// ScopeInfo::ScopeInfo(FunctionScope* scope) constructor). // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
if (function_ != NULL) { if (function_ != NULL) {
AllocateNonParameterLocal(function_); AllocateNonParameterLocal(function_->var());
} }
} }

19
deps/v8/src/scopes.h

@ -112,6 +112,11 @@ class Scope: public ZoneObject {
void Initialize(bool inside_with); 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 // Declarations
@ -130,7 +135,7 @@ class Scope: public ZoneObject {
// Declare a parameter in this scope. When there are duplicated // Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation // parameters the rightmost one 'wins'. However, the implementation
// expects all parameters to be declared and from left to right. // 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 // Declare a local variable in this scope. If the variable has been
// declared before, the previously declared variable is returned. // declared before, the previously declared variable is returned.
@ -182,6 +187,10 @@ class Scope: public ZoneObject {
// Check if the scope has (at least) one illegal redeclaration. // Check if the scope has (at least) one illegal redeclaration.
bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; } 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. // Scope-specific info.
@ -235,7 +244,7 @@ class Scope: public ZoneObject {
// The variable holding the function literal for named function // The variable holding the function literal for named function
// literals, or NULL. // literals, or NULL.
// Only valid for function scopes. // Only valid for function scopes.
Variable* function() const { VariableProxy* function() const {
ASSERT(is_function_scope()); ASSERT(is_function_scope());
return function_; return function_;
} }
@ -354,7 +363,7 @@ class Scope: public ZoneObject {
// Convenience variable. // Convenience variable.
Variable* receiver_; Variable* receiver_;
// Function variable, if any; function scopes only. // Function variable, if any; function scopes only.
Variable* function_; VariableProxy* function_;
// Convenience variable; function scopes only. // Convenience variable; function scopes only.
Variable* arguments_; Variable* arguments_;
@ -435,10 +444,6 @@ class Scope: public ZoneObject {
// Construct a catch scope with a binding for the name. // Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_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) { void AddInnerScope(Scope* inner_scope) {
if (inner_scope != NULL) { if (inner_scope != NULL) {
inner_scopes_.Add(inner_scope); inner_scopes_.Add(inner_scope);

3
deps/v8/src/spaces-inl.h

@ -155,7 +155,8 @@ uint32_t Page::GetRegionMaskForAddress(Address addr) {
uint32_t Page::GetRegionMaskForSpan(Address start, int length_in_bytes) { uint32_t Page::GetRegionMaskForSpan(Address start, int length_in_bytes) {
uint32_t result = 0; uint32_t result = 0;
if (length_in_bytes >= kPageSize) { static const intptr_t kRegionMask = (1 << kRegionSizeLog2) - 1;
if (length_in_bytes + (OffsetFrom(start) & kRegionMask) >= kPageSize) {
result = kAllRegionsDirtyMarks; result = kAllRegionsDirtyMarks;
} else if (length_in_bytes > 0) { } else if (length_in_bytes > 0) {
int start_region = GetRegionNumberForAddress(start); int start_region = GetRegionNumberForAddress(start);

60
deps/v8/src/string.js

@ -911,50 +911,47 @@ function ReplaceResultBuilder(str) {
this.special_string = str; this.special_string = str;
} }
ReplaceResultBuilder.prototype.__proto__ = null; SetUpLockedPrototype(ReplaceResultBuilder,
$Array("elements", "special_string"), $Array(
"add", function(str) {
ReplaceResultBuilder.prototype.add = function(str) { str = TO_STRING_INLINE(str);
str = TO_STRING_INLINE(str); if (str.length > 0) this.elements.push(str);
if (str.length > 0) this.elements.push(str); },
} "addSpecialSlice", function(start, end) {
var len = end - start;
if (start < 0 || len <= 0) return;
ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { if (start < 0x80000 && len < 0x800) {
var len = end - start; this.elements.push((start << 11) | len);
if (start < 0 || len <= 0) return; } else {
if (start < 0x80000 && len < 0x800) { // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
this.elements.push((start << 11) | len); // so -len is a smi.
} else { var elements = this.elements;
// 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength, elements.push(-len);
// so -len is a smi. elements.push(start);
}
},
"generate", function() {
var elements = this.elements; var elements = this.elements;
elements.push(-len); return %StringBuilderConcat(elements, elements.length, this.special_string);
elements.push(start);
} }
} ));
ReplaceResultBuilder.prototype.generate = function() {
var elements = this.elements;
return %StringBuilderConcat(elements, elements.length, this.special_string);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupString() { function SetUpString() {
// Setup the constructor property on the String prototype object. %CheckIsBootstrapping();
// Set up the constructor property on the String prototype object.
%SetProperty($String.prototype, "constructor", $String, DONT_ENUM); %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( InstallFunctions($String, DONT_ENUM, $Array(
"fromCharCode", StringFromCharCode "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( InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array(
"valueOf", StringValueOf, "valueOf", StringValueOf,
"toString", StringToString, "toString", StringToString,
@ -994,5 +991,4 @@ function SetupString() {
)); ));
} }
SetUpString();
SetupString();

2
deps/v8/src/stub-cache.h

@ -357,7 +357,7 @@ class StubCache {
// shift are equal. Shifting down the length field to get the // shift are equal. Shifting down the length field to get the
// hash code would effectively throw away two bits of the hash // hash code would effectively throw away two bits of the hash
// code. // code.
ASSERT(kHeapObjectTagSize == String::kHashShift); STATIC_ASSERT(kHeapObjectTagSize == String::kHashShift);
// Compute the hash of the name (use entire hash field). // Compute the hash of the name (use entire hash field).
ASSERT(name->HasHashCode()); ASSERT(name->HasHashCode());
uint32_t field = name->hash_field(); uint32_t field = name->hash_field();

1
deps/v8/src/token.h

@ -71,6 +71,7 @@ namespace internal {
/* this block of enum values being contiguous and sorted in the */ \ /* this block of enum values being contiguous and sorted in the */ \
/* same order! */ \ /* same order! */ \
T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \ T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \
T(INIT_LET, "=init_let", 2) /* AST-use only. */ \
T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \ T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \ T(ASSIGN, "=", 2) \
T(ASSIGN_BIT_OR, "|=", 2) \ T(ASSIGN_BIT_OR, "|=", 2) \

7
deps/v8/src/uri.js

@ -392,8 +392,9 @@ function URIUnescape(str) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
function SetupURI() { function SetUpUri() {
// Setup non-enumerable URI functions on the global object and set %CheckIsBootstrapping();
// Set up non-enumerable URI functions on the global object and set
// their names. // their names.
InstallFunctions(global, DONT_ENUM, $Array( InstallFunctions(global, DONT_ENUM, $Array(
"escape", URIEscape, "escape", URIEscape,
@ -405,4 +406,4 @@ function SetupURI() {
)); ));
} }
SetupURI(); SetUpUri();

261
deps/v8/src/v8natives.js

@ -41,7 +41,6 @@
const $isNaN = GlobalIsNaN; const $isNaN = GlobalIsNaN;
const $isFinite = GlobalIsFinite; const $isFinite = GlobalIsFinite;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -66,28 +65,56 @@ function InstallFunctions(object, attributes, functions) {
// functions on String.prototype etc. and then restore the old function // functions on String.prototype etc. and then restore the old function
// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717 // with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
function InstallFunctionsOnHiddenPrototype(object, attributes, functions) { function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
%CheckIsBootstrapping();
var hidden_prototype = new $Object(); var hidden_prototype = new $Object();
%SetHiddenPrototype(object, hidden_prototype); %SetHiddenPrototype(object, hidden_prototype);
InstallFunctions(hidden_prototype, attributes, functions); 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 // ECMA 262 - 15.1.4
function GlobalIsNaN(number) { function GlobalIsNaN(number) {
var n = ToNumber(number); if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
return NUMBER_IS_NAN(n); return NUMBER_IS_NAN(number);
} }
// ECMA 262 - 15.1.5 // ECMA 262 - 15.1.5
function GlobalIsFinite(number) { function GlobalIsFinite(number) {
if (!IS_NUMBER(number)) number = NonNumberToNumber(number); if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
return NUMBER_IS_FINITE(number);
// NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN.
return %_IsSmi(number) || number - number == 0;
} }
@ -106,13 +133,16 @@ function GlobalParseInt(string, radix) {
// Truncate number. // Truncate number.
return string | 0; return string | 0;
} }
string = TO_STRING_INLINE(string);
radix = radix | 0; radix = radix | 0;
} else { } else {
// The spec says ToString should be evaluated before ToInt32.
string = TO_STRING_INLINE(string);
radix = TO_INT32(radix); radix = TO_INT32(radix);
if (!(radix == 0 || (2 <= radix && radix <= 36))) if (!(radix == 0 || (2 <= radix && radix <= 36)))
return $NaN; return $NaN;
} }
string = TO_STRING_INLINE(string);
if (%_HasCachedArrayIndex(string) && if (%_HasCachedArrayIndex(string) &&
(radix == 0 || radix == 10)) { (radix == 0 || radix == 10)) {
return %_GetCachedArrayIndex(string); return %_GetCachedArrayIndex(string);
@ -159,8 +189,9 @@ function GlobalEval(x) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Set up global object.
function SetupGlobal() { function SetUpGlobal() {
%CheckIsBootstrapping();
// ECMA 262 - 15.1.1.1. // ECMA 262 - 15.1.1.1.
%SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE); %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
@ -170,7 +201,7 @@ function SetupGlobal() {
// ECMA-262 - 15.1.1.3. // ECMA-262 - 15.1.1.3.
%SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE); %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( InstallFunctions(global, DONT_ENUM, $Array(
"isNaN", GlobalIsNaN, "isNaN", GlobalIsNaN,
"isFinite", GlobalIsFinite, "isFinite", GlobalIsFinite,
@ -180,8 +211,7 @@ function SetupGlobal() {
)); ));
} }
SetupGlobal(); SetUpGlobal();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Boolean (first part of definition) // Boolean (first part of definition)
@ -478,106 +508,83 @@ function PropertyDescriptor() {
this.hasSetter_ = false; this.hasSetter_ = false;
} }
PropertyDescriptor.prototype.__proto__ = null; SetUpLockedPrototype(PropertyDescriptor, $Array(
"value_",
PropertyDescriptor.prototype.toString = function() { "hasValue_",
return "[object PropertyDescriptor]"; "writable_",
}; "hasWritable_",
"enumerable_",
PropertyDescriptor.prototype.setValue = function(value) { "hasEnumerable_",
this.value_ = value; "configurable_",
this.hasValue_ = true; "hasConfigurable_",
} "get_",
"hasGetter_",
"set_",
PropertyDescriptor.prototype.getValue = function() { "hasSetter_"
return this.value_; ), $Array(
} "toString", function() {
return "[object PropertyDescriptor]";
},
PropertyDescriptor.prototype.hasValue = function() { "setValue", function(value) {
return this.hasValue_; this.value_ = value;
} this.hasValue_ = true;
},
"getValue", function() {
PropertyDescriptor.prototype.setEnumerable = function(enumerable) { return this.value_;
this.enumerable_ = enumerable; },
this.hasEnumerable_ = true; "hasValue", function() {
} return this.hasValue_;
},
"setEnumerable", function(enumerable) {
PropertyDescriptor.prototype.isEnumerable = function () { this.enumerable_ = enumerable;
return this.enumerable_; this.hasEnumerable_ = true;
} },
"isEnumerable", function () {
return this.enumerable_;
PropertyDescriptor.prototype.hasEnumerable = function() { },
return this.hasEnumerable_; "hasEnumerable", function() {
} return this.hasEnumerable_;
},
"setWritable", function(writable) {
PropertyDescriptor.prototype.setWritable = function(writable) { this.writable_ = writable;
this.writable_ = writable; this.hasWritable_ = true;
this.hasWritable_ = true; },
} "isWritable", function() {
return this.writable_;
},
PropertyDescriptor.prototype.isWritable = function() { "hasWritable", function() {
return this.writable_; return this.hasWritable_;
} },
"setConfigurable", function(configurable) {
this.configurable_ = configurable;
PropertyDescriptor.prototype.hasWritable = function() { this.hasConfigurable_ = true;
return this.hasWritable_; },
} "hasConfigurable", function() {
return this.hasConfigurable_;
},
PropertyDescriptor.prototype.setConfigurable = function(configurable) { "isConfigurable", function() {
this.configurable_ = configurable; return this.configurable_;
this.hasConfigurable_ = true; },
} "setGet", function(get) {
this.get_ = get;
this.hasGetter_ = true;
PropertyDescriptor.prototype.hasConfigurable = function() { },
return this.hasConfigurable_; "getGet", function() {
} return this.get_;
},
"hasGetter", function() {
PropertyDescriptor.prototype.isConfigurable = function() { return this.hasGetter_;
return this.configurable_; },
} "setSet", function(set) {
this.set_ = set;
this.hasSetter_ = true;
PropertyDescriptor.prototype.setGet = function(get) { },
this.get_ = get; "getSet", function() {
this.hasGetter_ = true; return this.set_;
} },
"hasSetter", function() {
return this.hasSetter_;
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_;
}
// Converts an array returned from Runtime_GetOwnProperty to an actual // Converts an array returned from Runtime_GetOwnProperty to an actual
@ -1165,10 +1172,11 @@ function ObjectIsExtensible(obj) {
%SetExpectedNumberOfProperties($Object, 4); %SetExpectedNumberOfProperties($Object, 4);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Object
function SetUpObject() {
function SetupObject() { %CheckIsBootstrapping();
// Setup non-enumerable functions on the Object.prototype object. // Set Up non-enumerable functions on the Object.prototype object.
InstallFunctions($Object.prototype, DONT_ENUM, $Array( InstallFunctions($Object.prototype, DONT_ENUM, $Array(
"toString", ObjectToString, "toString", ObjectToString,
"toLocaleString", ObjectToLocaleString, "toLocaleString", ObjectToLocaleString,
@ -1198,8 +1206,7 @@ function SetupObject() {
)); ));
} }
SetupObject(); SetUpObject();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Boolean // Boolean
@ -1230,14 +1237,16 @@ function BooleanValueOf() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function SetupBoolean() { function SetUpBoolean () {
%CheckIsBootstrapping();
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array( InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString, "toString", BooleanToString,
"valueOf", BooleanValueOf "valueOf", BooleanValueOf
)); ));
} }
SetupBoolean(); SetUpBoolean();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Number // Number
@ -1351,9 +1360,10 @@ function NumberToPrecision(precision) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function SetupNumber() { function SetUpNumber() {
%CheckIsBootstrapping();
%OptimizeObjectForAddingMultipleProperties($Number.prototype, 8); %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); %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
%OptimizeObjectForAddingMultipleProperties($Number, 5); %OptimizeObjectForAddingMultipleProperties($Number, 5);
@ -1382,7 +1392,7 @@ function SetupNumber() {
DONT_ENUM | DONT_DELETE | READ_ONLY); DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Number); %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( InstallFunctions($Number.prototype, DONT_ENUM, $Array(
"toString", NumberToString, "toString", NumberToString,
"toLocaleString", NumberToLocaleString, "toLocaleString", NumberToLocaleString,
@ -1393,7 +1403,7 @@ function SetupNumber() {
)); ));
} }
SetupNumber(); SetUpNumber();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -1522,11 +1532,12 @@ function NewFunction(arg1) { // length == 1
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function SetupFunction() { function SetUpFunction() {
%CheckIsBootstrapping();
InstallFunctions($Function.prototype, DONT_ENUM, $Array( InstallFunctions($Function.prototype, DONT_ENUM, $Array(
"bind", FunctionBind, "bind", FunctionBind,
"toString", FunctionToString "toString", FunctionToString
)); ));
} }
SetupFunction(); SetUpFunction();

31
deps/v8/src/variables.cc

@ -53,34 +53,6 @@ const char* Variable::Mode2String(Mode mode) {
} }
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, Variable::Variable(Scope* scope,
Handle<String> name, Handle<String> name,
Mode mode, Mode mode,
@ -90,8 +62,9 @@ Variable::Variable(Scope* scope,
name_(name), name_(name),
mode_(mode), mode_(mode),
kind_(kind), kind_(kind),
location_(UNALLOCATED),
index_(-1),
local_if_not_shadowed_(NULL), local_if_not_shadowed_(NULL),
rewrite_(NULL),
is_valid_LHS_(is_valid_LHS), is_valid_LHS_(is_valid_LHS),
is_accessed_from_inner_function_scope_(false), is_accessed_from_inner_function_scope_(false),
is_used_(false) { is_used_(false) {

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save