Browse Source

Merge branch 'V8-3.4'

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
fea524e145
  1. 39
      deps/v8/ChangeLog
  2. 14
      deps/v8/SConstruct
  3. 124
      deps/v8/include/v8.h
  4. 2
      deps/v8/preparser/preparser-process.cc
  5. 7
      deps/v8/samples/shell.cc
  6. 19
      deps/v8/src/SConscript
  7. 181
      deps/v8/src/api.cc
  8. 7
      deps/v8/src/arm/assembler-arm.cc
  9. 14
      deps/v8/src/arm/assembler-arm.h
  10. 1
      deps/v8/src/arm/code-stubs-arm.cc
  11. 35
      deps/v8/src/arm/lithium-arm.cc
  12. 40
      deps/v8/src/arm/lithium-arm.h
  13. 93
      deps/v8/src/arm/lithium-codegen-arm.cc
  14. 14
      deps/v8/src/arm/macro-assembler-arm.cc
  15. 190
      deps/v8/src/arm/stub-cache-arm.cc
  16. 6
      deps/v8/src/array.js
  17. 15
      deps/v8/src/assembler.cc
  18. 6
      deps/v8/src/assembler.h
  19. 56
      deps/v8/src/ast-inl.h
  20. 68
      deps/v8/src/ast.cc
  21. 213
      deps/v8/src/ast.h
  22. 1
      deps/v8/src/bootstrapper.cc
  23. 4
      deps/v8/src/builtins.cc
  24. 5
      deps/v8/src/code-stubs.cc
  25. 2
      deps/v8/src/compiler.cc
  26. 9
      deps/v8/src/compiler.h
  27. 2
      deps/v8/src/contexts.h
  28. 7
      deps/v8/src/conversions-inl.h
  29. 232
      deps/v8/src/d8.cc
  30. 27
      deps/v8/src/d8.gyp
  31. 111
      deps/v8/src/d8.h
  32. 14
      deps/v8/src/debug.cc
  33. 7
      deps/v8/src/factory.cc
  34. 3
      deps/v8/src/factory.h
  35. 1
      deps/v8/src/frames.cc
  36. 1
      deps/v8/src/full-codegen.cc
  37. 4
      deps/v8/src/globals.h
  38. 33
      deps/v8/src/heap.cc
  39. 5
      deps/v8/src/heap.h
  40. 22
      deps/v8/src/hydrogen-instructions.cc
  41. 101
      deps/v8/src/hydrogen-instructions.h
  42. 86
      deps/v8/src/hydrogen.cc
  43. 1
      deps/v8/src/ia32/code-stubs-ia32.cc
  44. 69
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  45. 7
      deps/v8/src/ia32/lithium-codegen-ia32.h
  46. 35
      deps/v8/src/ia32/lithium-ia32.cc
  47. 41
      deps/v8/src/ia32/lithium-ia32.h
  48. 3
      deps/v8/src/ia32/macro-assembler-ia32.cc
  49. 157
      deps/v8/src/ia32/stub-cache-ia32.cc
  50. 8
      deps/v8/src/jsregexp.cc
  51. 19
      deps/v8/src/messages.js
  52. 7
      deps/v8/src/mips/assembler-mips.cc
  53. 14
      deps/v8/src/mips/assembler-mips.h
  54. 1
      deps/v8/src/mips/code-stubs-mips.cc
  55. 5
      deps/v8/src/mips/macro-assembler-mips.cc
  56. 189
      deps/v8/src/mips/stub-cache-mips.cc
  57. 41
      deps/v8/src/mirror-debugger.js
  58. 2
      deps/v8/src/natives.h
  59. 3
      deps/v8/src/objects-debug.cc
  60. 37
      deps/v8/src/objects-inl.h
  61. 255
      deps/v8/src/objects.cc
  62. 72
      deps/v8/src/objects.h
  63. 186
      deps/v8/src/parser.cc
  64. 5
      deps/v8/src/parser.h
  65. 1
      deps/v8/src/platform-linux.cc
  66. 5
      deps/v8/src/platform-nullos.cc
  67. 9
      deps/v8/src/platform-posix.cc
  68. 6
      deps/v8/src/platform-win32.cc
  69. 4
      deps/v8/src/platform.h
  70. 16
      deps/v8/src/rewriter.cc
  71. 273
      deps/v8/src/runtime.cc
  72. 7
      deps/v8/src/runtime.h
  73. 3
      deps/v8/src/runtime.js
  74. 89
      deps/v8/src/scopes.cc
  75. 6
      deps/v8/src/scopes.h
  76. 57
      deps/v8/src/spaces.cc
  77. 3
      deps/v8/src/spaces.h
  78. 5
      deps/v8/src/stub-cache.h
  79. 18
      deps/v8/src/v8.cc
  80. 3
      deps/v8/src/v8.h
  81. 10
      deps/v8/src/v8globals.h
  82. 43
      deps/v8/src/v8natives.js
  83. 4
      deps/v8/src/version.cc
  84. 2
      deps/v8/src/x64/assembler-x64.h
  85. 2
      deps/v8/src/x64/code-stubs-x64.cc
  86. 14
      deps/v8/src/x64/deoptimizer-x64.cc
  87. 2
      deps/v8/src/x64/full-codegen-x64.cc
  88. 66
      deps/v8/src/x64/lithium-codegen-x64.cc
  89. 5
      deps/v8/src/x64/lithium-codegen-x64.h
  90. 35
      deps/v8/src/x64/lithium-x64.cc
  91. 40
      deps/v8/src/x64/lithium-x64.h
  92. 3
      deps/v8/src/x64/macro-assembler-x64.cc
  93. 2
      deps/v8/src/x64/regexp-macro-assembler-x64.cc
  94. 140
      deps/v8/src/x64/stub-cache-x64.cc
  95. 2
      deps/v8/src/zone.h
  96. 24
      deps/v8/test/cctest/SConscript
  97. 41
      deps/v8/test/cctest/cctest.gyp
  98. 22
      deps/v8/test/cctest/log-eq-of-logging-and-traversal.js
  99. 110
      deps/v8/test/cctest/test-api.cc
  100. 2
      deps/v8/test/cctest/test-ast.cc

39
deps/v8/ChangeLog

@ -1,3 +1,42 @@
2011-07-20: Version 3.4.14
Fix the debugger for strict-mode functions. (Chromium issue 89236)
Add GetPropertyAttribute method for Object in the API. (Patch by Peter Varga)
Fix -Wunused-but-set-variable for gcc-4.6 on x64. (Issue 1291)
2011-07-18: Version 3.4.13
Improved debugger support to allow inspection of optimized frames (issue
1140).
Fixed a bug in prototype transitions cache clearing introduced by r8165.
Fixed shortcutting bug in HInferRepresentation. Patch by Andy Wingo.
Fixed a memory leak in sample/shell.cc (dispose semaphores).
Simplified HClampToUint8. Patch by Andy Wingo.
Exposed APIs for detecting boxed primitives, native errors. Patch by
Luke Zarko.
Added map check for COW elements to crankshaft array handling code
(issue 1560).
Sample shell and (a light version of) D8 links against a shared library
now.
Fixed bug in array filter and reduce functions (issue 1559).
Avoid TLS load in AstNode constructor.
Introduced a random entropy source which can optionally be provided at
initialization. (Chromium issue 89462).
2011-07-13: Version 3.4.12 2011-07-13: Version 3.4.12
Added --prof profiling option to d8 shell. Added --prof profiling option to d8 shell.

14
deps/v8/SConstruct

@ -404,6 +404,7 @@ CCTEST_EXTRA_FLAGS = {
}, },
'os:linux': { 'os:linux': {
'LIBS': ['pthread'], 'LIBS': ['pthread'],
'CCFLAGS': ['-Wno-unused-but-set-variable'],
}, },
'os:macos': { 'os:macos': {
'LIBS': ['pthread'], 'LIBS': ['pthread'],
@ -773,6 +774,13 @@ PREPARSER_FLAGS = {
D8_FLAGS = { D8_FLAGS = {
'all': {
'library:shared': {
'CPPDEFINES': ['V8_SHARED'],
'LIBS': ['v8'],
'LIBPATH': ['.']
},
},
'gcc': { 'gcc': {
'all': { 'all': {
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
@ -1370,7 +1378,11 @@ def BuildSpecific(env, mode, env_overrides, tools):
d8_env = Environment(tools=tools) d8_env = Environment(tools=tools)
d8_env.Replace(**context.flags['d8']) d8_env.Replace(**context.flags['d8'])
context.ApplyEnvOverrides(d8_env) context.ApplyEnvOverrides(d8_env)
shell = d8_env.Program('d8' + suffix, object_files + shell_files) if context.options['library'] == 'static':
shell = d8_env.Program('d8' + suffix, object_files + shell_files)
else:
shell = d8_env.Program('d8' + suffix, shell_files)
d8_env.Depends(shell, library)
context.d8_targets.append(shell) context.d8_targets.append(shell)
for sample in context.samples: for sample in context.samples:

124
deps/v8/include/v8.h

@ -80,9 +80,11 @@ namespace v8 {
class Context; class Context;
class String; class String;
class StringObject;
class Value; class Value;
class Utils; class Utils;
class Number; class Number;
class NumberObject;
class Object; class Object;
class Array; class Array;
class Int32; class Int32;
@ -90,6 +92,7 @@ class Uint32;
class External; class External;
class Primitive; class Primitive;
class Boolean; class Boolean;
class BooleanObject;
class Integer; class Integer;
class Function; class Function;
class Date; class Date;
@ -928,6 +931,26 @@ class Value : public Data {
*/ */
V8EXPORT bool IsDate() const; V8EXPORT bool IsDate() const;
/**
* Returns true if this value is a Boolean object.
*/
V8EXPORT bool IsBooleanObject() const;
/**
* Returns true if this value is a Number object.
*/
V8EXPORT bool IsNumberObject() const;
/**
* Returns true if this value is a String object.
*/
V8EXPORT bool IsStringObject() const;
/**
* Returns true if this value is a NativeError.
*/
V8EXPORT bool IsNativeError() const;
/** /**
* Returns true if this value is a RegExp. * Returns true if this value is a RegExp.
*/ */
@ -1435,6 +1458,13 @@ class Object : public Value {
V8EXPORT Local<Value> Get(uint32_t index); V8EXPORT Local<Value> Get(uint32_t index);
/**
* Gets the property attributes of a property which can be None or
* any combination of ReadOnly, DontEnum and DontDelete. Returns
* None when the property doesn't exist.
*/
V8EXPORT PropertyAttribute GetPropertyAttributes(Handle<Value> key);
// TODO(1245389): Replace the type-specific versions of these // TODO(1245389): Replace the type-specific versions of these
// functions with generic ones that accept a Handle<Value> key. // functions with generic ones that accept a Handle<Value> key.
V8EXPORT bool Has(Handle<String> key); V8EXPORT bool Has(Handle<String> key);
@ -1744,6 +1774,63 @@ class Date : public Object {
}; };
/**
* A Number object (ECMA-262, 4.3.21).
*/
class NumberObject : public Object {
public:
V8EXPORT static Local<Value> New(double value);
/**
* Returns the Number held by the object.
*/
V8EXPORT double NumberValue() const;
static inline NumberObject* Cast(v8::Value* obj);
private:
V8EXPORT static void CheckCast(v8::Value* obj);
};
/**
* A Boolean object (ECMA-262, 4.3.15).
*/
class BooleanObject : public Object {
public:
V8EXPORT static Local<Value> New(bool value);
/**
* Returns the Boolean held by the object.
*/
V8EXPORT bool BooleanValue() const;
static inline BooleanObject* Cast(v8::Value* obj);
private:
V8EXPORT static void CheckCast(v8::Value* obj);
};
/**
* A String object (ECMA-262, 4.3.18).
*/
class StringObject : public Object {
public:
V8EXPORT static Local<Value> New(Handle<String> value);
/**
* Returns the String held by the object.
*/
V8EXPORT Local<String> StringValue() const;
static inline StringObject* Cast(v8::Value* obj);
private:
V8EXPORT static void CheckCast(v8::Value* obj);
};
/** /**
* An instance of the built-in RegExp constructor (ECMA-262, 15.10). * An instance of the built-in RegExp constructor (ECMA-262, 15.10).
*/ */
@ -2721,6 +2808,13 @@ class V8EXPORT StartupDataDecompressor { // NOLINT
char** raw_data; char** raw_data;
}; };
/**
* EntropySource is used as a callback function when v8 needs a source
* of entropy.
*/
typedef bool (*EntropySource)(unsigned char* buffer, size_t length);
/** /**
* Container class for static utility functions. * Container class for static utility functions.
*/ */
@ -2945,6 +3039,12 @@ class V8EXPORT V8 {
*/ */
static bool Initialize(); static bool Initialize();
/**
* Allows the host application to provide a callback which can be used
* as a source of entropy for random number generators.
*/
static void SetEntropySource(EntropySource source);
/** /**
* Adjusts the amount of registered external memory. Used to give * Adjusts the amount of registered external memory. Used to give
* V8 an indication of the amount of externally allocated memory * V8 an indication of the amount of externally allocated memory
@ -4010,6 +4110,30 @@ Date* Date::Cast(v8::Value* value) {
} }
StringObject* StringObject::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<StringObject*>(value);
}
NumberObject* NumberObject::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<NumberObject*>(value);
}
BooleanObject* BooleanObject::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
#endif
return static_cast<BooleanObject*>(value);
}
RegExp* RegExp::Cast(v8::Value* value) { RegExp* RegExp::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS #ifdef V8_ENABLE_CHECKS
CheckCast(value); CheckCast(value);

2
deps/v8/preparser/preparser-process.cc

@ -208,7 +208,7 @@ void fail(v8::PreParserData* data, const char* message, ...) {
fflush(stderr); fflush(stderr);
} }
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}; }
bool IsFlag(const char* arg) { bool IsFlag(const char* arg) {

7
deps/v8/samples/shell.cc

@ -95,6 +95,13 @@ class SourceGroup {
begin_offset_(0), begin_offset_(0),
end_offset_(0) { } end_offset_(0) { }
#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
~SourceGroup() {
delete next_semaphore_;
delete done_semaphore_;
}
#endif // USING_V8_SHARED
void Begin(char** argv, int offset) { void Begin(char** argv, int offset) {
argv_ = const_cast<const char**>(argv); argv_ = const_cast<const char**>(argv);
begin_offset_ = offset; begin_offset_ = offset;

19
deps/v8/src/SConscript

@ -243,7 +243,14 @@ PREPARSER_SOURCES = {
} }
D8_FILES = { D8_LIGHT_FILES = {
'all': [
'd8.cc'
]
}
D8_FULL_FILES = {
'all': [ 'all': [
'd8.cc', 'd8-debug.cc' 'd8.cc', 'd8-debug.cc'
], ],
@ -323,11 +330,15 @@ def ConfigureObjectFiles():
# Build the standard platform-independent source files. # Build the standard platform-independent source files.
source_files = context.GetRelevantSources(SOURCES) source_files = context.GetRelevantSources(SOURCES)
d8_files = context.GetRelevantSources(D8_FILES)
d8_js = env.JS2C('d8-js.cc', 'd8.js', **{'TYPE': 'D8', 'COMPRESSION': 'off'}) d8_js = env.JS2C('d8-js.cc', 'd8.js', **{'TYPE': 'D8', 'COMPRESSION': 'off'})
d8_js_obj = context.ConfigureObject(env, d8_js, CPPPATH=['.']) d8_js_obj = context.ConfigureObject(env, d8_js, CPPPATH=['.'])
d8_objs = [context.ConfigureObject(env, [d8_files]), d8_js_obj] if context.options['library'] == 'shared':
d8_files = context.GetRelevantSources(D8_LIGHT_FILES)
d8_objs = []
else:
d8_files = context.GetRelevantSources(D8_FULL_FILES)
d8_objs = [d8_js_obj]
d8_objs.append(context.ConfigureObject(env, [d8_files]))
# Combine the JavaScript library files into a single C++ file and # Combine the JavaScript library files into a single C++ file and
# compile it. # compile it.

181
deps/v8/src/api.cc

@ -2167,6 +2167,65 @@ bool Value::IsDate() const {
} }
bool Value::IsStringObject() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsStringObject()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->HasSpecificClassOf(isolate->heap()->String_symbol());
}
bool Value::IsNumberObject() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsNumberObject()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->HasSpecificClassOf(isolate->heap()->Number_symbol());
}
static i::Object* LookupBuiltin(i::Isolate* isolate,
const char* builtin_name) {
i::Handle<i::String> symbol =
isolate->factory()->LookupAsciiSymbol(builtin_name);
i::Handle<i::JSBuiltinsObject> builtins = isolate->js_builtins_object();
return builtins->GetPropertyNoExceptionThrown(*symbol);
}
static bool CheckConstructor(i::Isolate* isolate,
i::Handle<i::JSObject> obj,
const char* class_name) {
return obj->map()->constructor() == LookupBuiltin(isolate, class_name);
}
bool Value::IsNativeError() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsNativeError()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
if (obj->IsJSObject()) {
i::Handle<i::JSObject> js_obj(i::JSObject::cast(*obj));
return CheckConstructor(isolate, js_obj, "$Error") ||
CheckConstructor(isolate, js_obj, "$EvalError") ||
CheckConstructor(isolate, js_obj, "$RangeError") ||
CheckConstructor(isolate, js_obj, "$ReferenceError") ||
CheckConstructor(isolate, js_obj, "$SyntaxError") ||
CheckConstructor(isolate, js_obj, "$TypeError") ||
CheckConstructor(isolate, js_obj, "$URIError");
} else {
return false;
}
}
bool Value::IsBooleanObject() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::Value::IsBooleanObject()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this);
return obj->HasSpecificClassOf(isolate->heap()->Boolean_symbol());
}
bool Value::IsRegExp() const { bool Value::IsRegExp() const {
if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsRegExp()")) return false; if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsRegExp()")) return false;
i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::Object> obj = Utils::OpenHandle(this);
@ -2362,6 +2421,36 @@ void v8::Date::CheckCast(v8::Value* that) {
} }
void v8::StringObject::CheckCast(v8::Value* that) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::StringObject::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->HasSpecificClassOf(isolate->heap()->String_symbol()),
"v8::StringObject::Cast()",
"Could not convert to StringObject");
}
void v8::NumberObject::CheckCast(v8::Value* that) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::NumberObject::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Number_symbol()),
"v8::NumberObject::Cast()",
"Could not convert to NumberObject");
}
void v8::BooleanObject::CheckCast(v8::Value* that) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::BooleanObject::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that);
ApiCheck(obj->HasSpecificClassOf(isolate->heap()->Boolean_symbol()),
"v8::BooleanObject::Cast()",
"Could not convert to BooleanObject");
}
void v8::RegExp::CheckCast(v8::Value* that) { void v8::RegExp::CheckCast(v8::Value* that) {
if (IsDeadCheck(i::Isolate::Current(), "v8::RegExp::Cast()")) return; if (IsDeadCheck(i::Isolate::Current(), "v8::RegExp::Cast()")) return;
i::Handle<i::Object> obj = Utils::OpenHandle(that); i::Handle<i::Object> obj = Utils::OpenHandle(that);
@ -2705,6 +2794,26 @@ Local<Value> v8::Object::Get(uint32_t index) {
} }
PropertyAttribute v8::Object::GetPropertyAttributes(v8::Handle<Value> key) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::GetPropertyAttribute()",
return static_cast<PropertyAttribute>(NONE));
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
if (!key_obj->IsString()) {
EXCEPTION_PREAMBLE(isolate);
key_obj = i::Execution::ToString(key_obj, &has_pending_exception);
EXCEPTION_BAILOUT_CHECK(isolate, static_cast<PropertyAttribute>(NONE));
}
i::Handle<i::String> key_string = i::Handle<i::String>::cast(key_obj);
PropertyAttributes result = self->GetPropertyAttribute(*key_string);
if (result == ABSENT) return static_cast<PropertyAttribute>(NONE);
return static_cast<PropertyAttribute>(result);
}
Local<Value> v8::Object::GetPrototype() { Local<Value> v8::Object::GetPrototype() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::GetPrototype()", ON_BAILOUT(isolate, "v8::Object::GetPrototype()",
@ -3844,6 +3953,11 @@ bool v8::V8::Initialize() {
} }
void v8::V8::SetEntropySource(EntropySource source) {
i::V8::SetEntropySource(source);
}
bool v8::V8::Dispose() { bool v8::V8::Dispose() {
i::Isolate* isolate = i::Isolate::Current(); i::Isolate* isolate = i::Isolate::Current();
if (!ApiCheck(isolate != NULL && isolate->IsDefaultIsolate(), if (!ApiCheck(isolate != NULL && isolate->IsDefaultIsolate(),
@ -4427,6 +4541,73 @@ Local<v8::Object> v8::Object::New() {
} }
Local<v8::Value> v8::NumberObject::New(double value) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::NumberObject::New()");
LOG_API(isolate, "NumberObject::New");
ENTER_V8(isolate);
i::Handle<i::Object> number = isolate->factory()->NewNumber(value);
i::Handle<i::Object> obj = isolate->factory()->ToObject(number);
return Utils::ToLocal(obj);
}
double v8::NumberObject::NumberValue() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::NumberObject::NumberValue()")) return 0;
LOG_API(isolate, "NumberObject::NumberValue");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
return jsvalue->value()->Number();
}
Local<v8::Value> v8::BooleanObject::New(bool value) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::BooleanObject::New()");
LOG_API(isolate, "BooleanObject::New");
ENTER_V8(isolate);
i::Handle<i::Object> boolean(value ? isolate->heap()->true_value()
: isolate->heap()->false_value());
i::Handle<i::Object> obj = isolate->factory()->ToObject(boolean);
return Utils::ToLocal(obj);
}
bool v8::BooleanObject::BooleanValue() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::BooleanObject::BooleanValue()")) return 0;
LOG_API(isolate, "BooleanObject::BooleanValue");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
return jsvalue->value()->IsTrue();
}
Local<v8::Value> v8::StringObject::New(Handle<String> value) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::StringObject::New()");
LOG_API(isolate, "StringObject::New");
ENTER_V8(isolate);
i::Handle<i::Object> obj =
isolate->factory()->ToObject(Utils::OpenHandle(*value));
return Utils::ToLocal(obj);
}
Local<v8::String> v8::StringObject::StringValue() const {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::StringObject::StringValue()")) {
return Local<v8::String>();
}
LOG_API(isolate, "StringObject::StringValue");
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
return Utils::ToLocal(
i::Handle<i::String>(i::String::cast(jsvalue->value())));
}
Local<v8::Value> v8::Date::New(double time) { Local<v8::Value> v8::Date::New(double time) {
i::Isolate* isolate = i::Isolate::Current(); i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::Date::New()"); EnsureInitializedForIsolate(isolate, "v8::Date::New()");

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

@ -326,7 +326,7 @@ Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size)
no_const_pool_before_ = 0; no_const_pool_before_ = 0;
first_const_pool_use_ = -1; first_const_pool_use_ = -1;
last_bound_pos_ = 0; last_bound_pos_ = 0;
ast_id_for_reloc_info_ = kNoASTId; ClearRecordedAstId();
} }
@ -2537,9 +2537,8 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
} }
ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
ASSERT(ast_id_for_reloc_info_ != kNoASTId); RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId());
RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_); ClearRecordedAstId();
ast_id_for_reloc_info_ = kNoASTId;
reloc_info_writer.Write(&reloc_info_with_ast_id); reloc_info_writer.Write(&reloc_info_with_ast_id);
} else { } else {
reloc_info_writer.Write(&rinfo); reloc_info_writer.Write(&rinfo);

14
deps/v8/src/arm/assembler-arm.h

@ -1178,7 +1178,17 @@ class Assembler : public AssemblerBase {
// Record the AST id of the CallIC being compiled, so that it can be placed // Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information. // in the relocation information.
void RecordAstId(unsigned ast_id) { ast_id_for_reloc_info_ = ast_id; } void SetRecordedAstId(unsigned ast_id) {
ASSERT(recorded_ast_id_ == kNoASTId);
recorded_ast_id_ = ast_id;
}
unsigned RecordedAstId() {
ASSERT(recorded_ast_id_ != kNoASTId);
return recorded_ast_id_;
}
void ClearRecordedAstId() { recorded_ast_id_ = kNoASTId; }
// Record a comment relocation entry that can be used by a disassembler. // Record a comment relocation entry that can be used by a disassembler.
// Use --code-comments to enable. // Use --code-comments to enable.
@ -1244,7 +1254,7 @@ class Assembler : public AssemblerBase {
// Relocation for a type-recording IC has the AST id added to it. This // Relocation for a type-recording IC has the AST id added to it. This
// member variable is a way to pass the information from the call site to // member variable is a way to pass the information from the call site to
// the relocation info. // the relocation info.
unsigned ast_id_for_reloc_info_; unsigned recorded_ast_id_;
bool emit_debug_code() const { return emit_debug_code_; } bool emit_debug_code() const { return emit_debug_code_; }

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

@ -4722,6 +4722,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ mov(r0, Operand(argc_)); // Setup the number of arguments. __ mov(r0, Operand(argc_)); // Setup the number of arguments.
__ mov(r2, Operand(0, RelocInfo::NONE)); __ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(r5, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} }

35
deps/v8/src/arm/lithium-arm.cc

@ -372,6 +372,15 @@ void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
} }
void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
elements()->PrintTo(stream);
stream->Add("[");
key()->PrintTo(stream);
stream->Add("] <- ");
value()->PrintTo(stream);
}
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) { void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream); object()->PrintTo(stream);
stream->Add("["); stream->Add("[");
@ -1844,6 +1853,18 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
} }
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
HLoadKeyedFastDoubleElement* instr) {
ASSERT(instr->representation().IsDouble());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* elements = UseTempRegister(instr->elements());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastDoubleElement* result =
new LLoadKeyedFastDoubleElement(elements, key);
return AssignEnvironment(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) { HLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind(); JSObject::ElementsKind elements_kind = instr->elements_kind();
@ -1897,6 +1918,20 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
} }
LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
HStoreKeyedFastDoubleElement* instr) {
ASSERT(instr->value()->representation().IsDouble());
ASSERT(instr->elements()->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* val = UseTempRegister(instr->value());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new LStoreKeyedFastDoubleElement(elements, key, val);
}
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) { HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation()); Representation representation(instr->value()->representation());

40
deps/v8/src/arm/lithium-arm.h

@ -121,6 +121,7 @@ class LCodeGen;
V(LoadFunctionPrototype) \ V(LoadFunctionPrototype) \
V(LoadGlobalCell) \ V(LoadGlobalCell) \
V(LoadGlobalGeneric) \ V(LoadGlobalGeneric) \
V(LoadKeyedFastDoubleElement) \
V(LoadKeyedFastElement) \ V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \ V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \ V(LoadKeyedSpecializedArrayElement) \
@ -147,6 +148,7 @@ class LCodeGen;
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreGlobalGeneric) \ V(StoreGlobalGeneric) \
V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \ V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \ V(StoreKeyedSpecializedArrayElement) \
@ -1137,6 +1139,22 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
}; };
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
inputs_[0] = elements;
inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
"load-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
@ -1597,6 +1615,28 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
}; };
class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyedFastDoubleElement(LOperand* elements,
LOperand* key,
LOperand* val) {
inputs_[0] = elements;
inputs_[1] = key;
inputs_[2] = val;
}
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
"store-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
virtual void PrintDataTo(StringStream* stream);
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
};
class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
public: public:
LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val) { LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val) {

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

@ -2433,6 +2433,48 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
} }
void LCodeGen::DoLoadKeyedFastDoubleElement(
LLoadKeyedFastDoubleElement* instr) {
Register elements = ToRegister(instr->elements());
bool key_is_constant = instr->key()->IsConstantOperand();
Register key = no_reg;
DwVfpRegister result = ToDoubleRegister(instr->result());
Register scratch = scratch0();
int shift_size =
ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
int constant_key = 0;
if (key_is_constant) {
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
if (constant_key & 0xF0000000) {
Abort("array index constant value too big.");
}
} else {
key = ToRegister(instr->key());
}
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(elements, elements, operand);
if (!key_is_constant) {
__ add(elements, elements,
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
}
if (instr->hydrogen()->RequiresHoleCheck()) {
// TODO(danno): If no hole check is required, there is no need to allocate
// elements into a temporary register, instead scratch can be used.
__ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
__ cmp(scratch, Operand(kHoleNanUpper32));
DeoptimizeIf(eq, instr->environment());
}
__ vldr(result, elements, 0);
}
void LCodeGen::DoLoadKeyedSpecializedArrayElement( void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) { LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer()); Register external_pointer = ToRegister(instr->external_pointer());
@ -2453,9 +2495,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS || if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3); CpuFeatures::Scope scope(VFP3);
DwVfpRegister result(ToDoubleRegister(instr->result())); DwVfpRegister result = ToDoubleRegister(instr->result());
Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size)) Operand operand = key_is_constant
: Operand(key, LSL, shift_size)); ? Operand(constant_key * (1 << shift_size))
: Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand); __ add(scratch0(), external_pointer, operand);
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ vldr(result.low(), scratch0(), 0); __ vldr(result.low(), scratch0(), 0);
@ -2464,7 +2507,7 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
__ vldr(result, scratch0(), 0); __ vldr(result, scratch0(), 0);
} }
} else { } else {
Register result(ToRegister(instr->result())); Register result = ToRegister(instr->result());
MemOperand mem_operand(key_is_constant MemOperand mem_operand(key_is_constant
? MemOperand(external_pointer, constant_key * (1 << shift_size)) ? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size)); : MemOperand(external_pointer, key, LSL, shift_size));
@ -3243,6 +3286,48 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
} }
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
DwVfpRegister value = ToDoubleRegister(instr->value());
Register elements = ToRegister(instr->elements());
Register key = no_reg;
Register scratch = scratch0();
bool key_is_constant = instr->key()->IsConstantOperand();
int constant_key = 0;
Label not_nan;
// Calculate the effective address of the slot in the array to store the
// double value.
if (key_is_constant) {
constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
if (constant_key & 0xF0000000) {
Abort("array index constant value too big.");
}
} else {
key = ToRegister(instr->key());
}
int shift_size = ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
Operand operand = key_is_constant
? Operand(constant_key * (1 << shift_size) +
FixedDoubleArray::kHeaderSize - kHeapObjectTag)
: Operand(key, LSL, shift_size);
__ add(scratch, elements, operand);
if (!key_is_constant) {
__ add(scratch, scratch,
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
}
// Check for NaN. All NaNs must be canonicalized.
__ VFPCompareAndSetFlags(value, value);
// Only load canonical NaN if the comparison above set the overflow.
__ Vmov(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double(), vs);
__ bind(&not_nan);
__ vstr(value, scratch, 0);
}
void LCodeGen::DoStoreKeyedSpecializedArrayElement( void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) { LStoreKeyedSpecializedArrayElement* instr) {

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

@ -192,13 +192,13 @@ void MacroAssembler::Call(Handle<Code> code,
bind(&start); bind(&start);
ASSERT(RelocInfo::IsCodeTarget(rmode)); ASSERT(RelocInfo::IsCodeTarget(rmode));
if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) { if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
ASSERT(ast_id_for_reloc_info_ == kNoASTId); SetRecordedAstId(ast_id);
ast_id_for_reloc_info_ = ast_id;
rmode = RelocInfo::CODE_TARGET_WITH_ID; rmode = RelocInfo::CODE_TARGET_WITH_ID;
} }
// 'code' is always generated ARM code, never THUMB code // 'code' is always generated ARM code, never THUMB code
Call(reinterpret_cast<Address>(code.location()), rmode, cond); Call(reinterpret_cast<Address>(code.location()), rmode, cond);
ASSERT_EQ(CallSize(code, rmode, cond), SizeOfCodeGeneratedSince(&start)); ASSERT_EQ(CallSize(code, rmode, ast_id, cond),
SizeOfCodeGeneratedSince(&start));
} }
@ -1862,7 +1862,7 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
void MacroAssembler::CallStub(CodeStub* stub, Condition cond) { void MacroAssembler::CallStub(CodeStub* stub, Condition cond) {
ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs.
Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond); Call(stub->GetCode(), RelocInfo::CODE_TARGET, kNoASTId, cond);
} }
@ -1872,7 +1872,8 @@ MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub, Condition cond) {
{ MaybeObject* maybe_result = stub->TryGetCode(); { MaybeObject* maybe_result = stub->TryGetCode();
if (!maybe_result->ToObject(&result)) return maybe_result; if (!maybe_result->ToObject(&result)) return maybe_result;
} }
Call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, cond); Handle<Code> code(Code::cast(result));
Call(code, RelocInfo::CODE_TARGET, kNoASTId, cond);
return result; return result;
} }
@ -2548,6 +2549,9 @@ void MacroAssembler::AssertFastElements(Register elements) {
LoadRoot(ip, Heap::kFixedArrayMapRootIndex); LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
cmp(elements, ip); cmp(elements, ip);
b(eq, &ok); b(eq, &ok);
LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex);
cmp(elements, ip);
b(eq, &ok);
LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
cmp(elements, ip); cmp(elements, ip);
b(eq, &ok); b(eq, &ok);

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

@ -4168,6 +4168,77 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
} }
void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
// -- r1 : receiver
// -----------------------------------
Label miss_force_generic, slow_allocate_heapnumber;
Register key_reg = r0;
Register receiver_reg = r1;
Register elements_reg = r2;
Register heap_number_reg = r2;
Register indexed_double_offset = r3;
Register scratch = r4;
Register scratch2 = r5;
Register scratch3 = r6;
Register heap_number_map = r7;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ JumpIfNotSmi(key_reg, &miss_force_generic);
// Get the elements array.
__ ldr(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
// Check that the key is within bounds.
__ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
__ cmp(key_reg, Operand(scratch));
__ b(hs, &miss_force_generic);
// Load the upper word of the double in the fixed array and test for NaN.
__ add(indexed_double_offset, elements_reg,
Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
__ ldr(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
__ cmp(scratch, Operand(kHoleNanUpper32));
__ b(&miss_force_generic, eq);
// Non-NaN. Allocate a new heap number and copy the double value into it.
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
__ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
heap_number_map, &slow_allocate_heapnumber);
// Don't need to reload the upper 32 bits of the double, it's already in
// scratch.
__ str(scratch, FieldMemOperand(heap_number_reg,
HeapNumber::kExponentOffset));
__ ldr(scratch, FieldMemOperand(indexed_double_offset,
FixedArray::kHeaderSize));
__ str(scratch, FieldMemOperand(heap_number_reg,
HeapNumber::kMantissaOffset));
__ mov(r0, heap_number_reg);
__ Ret();
__ bind(&slow_allocate_heapnumber);
Handle<Code> slow_ic =
masm->isolate()->builtins()->KeyedLoadIC_Slow();
__ Jump(slow_ic, RelocInfo::CODE_TARGET);
__ bind(&miss_force_generic);
Handle<Code> miss_ic =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
__ Jump(miss_ic, RelocInfo::CODE_TARGET);
}
void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array) { bool is_js_array) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
@ -4231,6 +4302,125 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
} }
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
MacroAssembler* masm,
bool is_js_array) {
// ----------- S t a t e -------------
// -- r0 : value
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
// -- r3 : scratch
// -- r4 : scratch
// -- r5 : scratch
// -----------------------------------
Label miss_force_generic, smi_value, is_nan, maybe_nan, have_double_value;
Register value_reg = r0;
Register key_reg = r1;
Register receiver_reg = r2;
Register scratch = r3;
Register elements_reg = r4;
Register mantissa_reg = r5;
Register exponent_reg = r6;
Register scratch4 = r7;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
__ JumpIfNotSmi(key_reg, &miss_force_generic);
__ ldr(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
// Check that the key is within bounds.
if (is_js_array) {
__ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
} else {
__ ldr(scratch,
FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
}
// Compare smis, unsigned compare catches both negative and out-of-bound
// indexes.
__ cmp(key_reg, scratch);
__ b(hs, &miss_force_generic);
// Handle smi values specially.
__ JumpIfSmi(value_reg, &smi_value);
// Ensure that the object is a heap number
__ CheckMap(value_reg,
scratch,
masm->isolate()->factory()->heap_number_map(),
&miss_force_generic,
DONT_DO_SMI_CHECK);
// Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
// in the exponent.
__ mov(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
__ ldr(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
__ cmp(exponent_reg, scratch);
__ b(ge, &maybe_nan);
__ ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
__ bind(&have_double_value);
__ add(scratch, elements_reg,
Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
__ str(mantissa_reg, FieldMemOperand(scratch, FixedDoubleArray::kHeaderSize));
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
__ str(exponent_reg, FieldMemOperand(scratch, offset));
__ Ret();
__ bind(&maybe_nan);
// Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
// it's an Infinity, and the non-NaN code path applies.
__ b(gt, &is_nan);
__ ldr(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
__ cmp(mantissa_reg, Operand(0));
__ b(eq, &have_double_value);
__ bind(&is_nan);
// Load canonical NaN for storing into the double array.
uint64_t nan_int64 = BitCast<uint64_t>(
FixedDoubleArray::canonical_not_the_hole_nan_as_double());
__ mov(mantissa_reg, Operand(static_cast<uint32_t>(nan_int64)));
__ mov(exponent_reg, Operand(static_cast<uint32_t>(nan_int64 >> 32)));
__ jmp(&have_double_value);
__ bind(&smi_value);
__ add(scratch, elements_reg,
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
__ add(scratch, scratch,
Operand(key_reg, LSL, kDoubleSizeLog2 - kSmiTagSize));
// scratch is now effective address of the double element
FloatingPointHelper::Destination destination;
if (CpuFeatures::IsSupported(VFP3)) {
destination = FloatingPointHelper::kVFPRegisters;
} else {
destination = FloatingPointHelper::kCoreRegisters;
}
__ SmiUntag(value_reg, value_reg);
FloatingPointHelper::ConvertIntToDouble(
masm, value_reg, destination,
d0, mantissa_reg, exponent_reg, // These are: double_dst, dst1, dst2.
scratch4, s2); // These are: scratch2, single_scratch.
if (destination == FloatingPointHelper::kVFPRegisters) {
CpuFeatures::Scope scope(VFP3);
__ vstr(d0, scratch, 0);
} else {
__ str(mantissa_reg, MemOperand(scratch, 0));
__ str(exponent_reg, MemOperand(scratch, Register::kSizeInBytes));
}
__ Ret();
// Handle store cache miss, replacing the ic with the generic stub.
__ bind(&miss_force_generic);
Handle<Code> ic =
masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
__ Jump(ic, RelocInfo::CODE_TARGET);
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

6
deps/v8/src/array.js

@ -999,7 +999,7 @@ function ArrayFilter(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 = this.length; var length = ToUint32(this.length);
var result = []; var result = [];
var result_length = 0; var result_length = 0;
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
@ -1236,7 +1236,7 @@ function ArrayReduce(callback, current) {
} }
// 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 = this.length; var length = ToUint32(this.length);
var i = 0; var i = 0;
find_initial: if (%_ArgumentsLength() < 2) { find_initial: if (%_ArgumentsLength() < 2) {
@ -1268,7 +1268,7 @@ function ArrayReduceRight(callback, current) {
if (!IS_FUNCTION(callback)) { if (!IS_FUNCTION(callback)) {
throw MakeTypeError('called_non_callable', [callback]); throw MakeTypeError('called_non_callable', [callback]);
} }
var i = this.length - 1; var i = ToUint32(this.length) - 1;
find_initial: if (%_ArgumentsLength() < 2) { find_initial: if (%_ArgumentsLength() < 2) {
for (; i >= 0; i--) { for (; i >= 0; i--) {

15
deps/v8/src/assembler.cc

@ -1,4 +1,4 @@
// Copyright (c) 1994-2006 Sun Microsystems Inc. // Copyright (c) 2011 Sun Microsystems Inc.
// All Rights Reserved. // All Rights Reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -71,7 +71,8 @@ const double DoubleConstant::one_half = 0.5;
const double DoubleConstant::minus_zero = -0.0; const double DoubleConstant::minus_zero = -0.0;
const double DoubleConstant::uint8_max_value = 255; const double DoubleConstant::uint8_max_value = 255;
const double DoubleConstant::zero = 0.0; const double DoubleConstant::zero = 0.0;
const double DoubleConstant::nan = OS::nan_value(); const double DoubleConstant::canonical_non_hole_nan = OS::nan_value();
const double DoubleConstant::the_hole_nan = BitCast<double>(kHoleNanInt64);
const double DoubleConstant::negative_infinity = -V8_INFINITY; const double DoubleConstant::negative_infinity = -V8_INFINITY;
const char* RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING"; const char* RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
@ -921,9 +922,15 @@ ExternalReference ExternalReference::address_of_negative_infinity() {
} }
ExternalReference ExternalReference::address_of_nan() { ExternalReference ExternalReference::address_of_canonical_non_hole_nan() {
return ExternalReference(reinterpret_cast<void*>( return ExternalReference(reinterpret_cast<void*>(
const_cast<double*>(&DoubleConstant::nan))); const_cast<double*>(&DoubleConstant::canonical_non_hole_nan)));
}
ExternalReference ExternalReference::address_of_the_hole_nan() {
return ExternalReference(reinterpret_cast<void*>(
const_cast<double*>(&DoubleConstant::the_hole_nan)));
} }

6
deps/v8/src/assembler.h

@ -70,7 +70,8 @@ class DoubleConstant: public AllStatic {
static const double zero; static const double zero;
static const double uint8_max_value; static const double uint8_max_value;
static const double negative_infinity; static const double negative_infinity;
static const double nan; static const double canonical_non_hole_nan;
static const double the_hole_nan;
}; };
@ -629,7 +630,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference address_of_zero(); static ExternalReference address_of_zero();
static ExternalReference address_of_uint8_max_value(); static ExternalReference address_of_uint8_max_value();
static ExternalReference address_of_negative_infinity(); static ExternalReference address_of_negative_infinity();
static ExternalReference address_of_nan(); static ExternalReference address_of_canonical_non_hole_nan();
static ExternalReference address_of_the_hole_nan();
static ExternalReference math_sin_double_function(Isolate* isolate); static ExternalReference math_sin_double_function(Isolate* isolate);
static ExternalReference math_cos_double_function(Isolate* isolate); static ExternalReference math_cos_double_function(Isolate* isolate);

56
deps/v8/src/ast-inl.h

@ -37,68 +37,76 @@ namespace v8 {
namespace internal { namespace internal {
SwitchStatement::SwitchStatement(ZoneStringList* labels) SwitchStatement::SwitchStatement(Isolate* isolate,
: BreakableStatement(labels, TARGET_FOR_ANONYMOUS), ZoneStringList* labels)
: BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
tag_(NULL), cases_(NULL) { tag_(NULL), cases_(NULL) {
} }
Block::Block(ZoneStringList* labels, int capacity, bool is_initializer_block) Block::Block(Isolate* isolate,
: BreakableStatement(labels, TARGET_FOR_NAMED_ONLY), ZoneStringList* labels,
int capacity,
bool is_initializer_block)
: BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity), statements_(capacity),
is_initializer_block_(is_initializer_block) { is_initializer_block_(is_initializer_block) {
} }
BreakableStatement::BreakableStatement(ZoneStringList* labels, Type type) BreakableStatement::BreakableStatement(Isolate* isolate,
ZoneStringList* labels,
Type type)
: labels_(labels), : labels_(labels),
type_(type), type_(type),
entry_id_(GetNextId()), entry_id_(GetNextId(isolate)),
exit_id_(GetNextId()) { exit_id_(GetNextId(isolate)) {
ASSERT(labels == NULL || labels->length() > 0); ASSERT(labels == NULL || labels->length() > 0);
} }
IterationStatement::IterationStatement(ZoneStringList* labels) IterationStatement::IterationStatement(Isolate* isolate, ZoneStringList* labels)
: BreakableStatement(labels, TARGET_FOR_ANONYMOUS), : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
body_(NULL), body_(NULL),
continue_target_(), continue_target_(),
osr_entry_id_(GetNextId()) { osr_entry_id_(GetNextId(isolate)) {
} }
DoWhileStatement::DoWhileStatement(ZoneStringList* labels) DoWhileStatement::DoWhileStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(labels), : IterationStatement(isolate, labels),
cond_(NULL), cond_(NULL),
condition_position_(-1), condition_position_(-1),
continue_id_(GetNextId()), continue_id_(GetNextId(isolate)),
back_edge_id_(GetNextId()) { back_edge_id_(GetNextId(isolate)) {
} }
WhileStatement::WhileStatement(ZoneStringList* labels) WhileStatement::WhileStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(labels), : IterationStatement(isolate, labels),
cond_(NULL), cond_(NULL),
may_have_function_literal_(true), may_have_function_literal_(true),
body_id_(GetNextId()) { body_id_(GetNextId(isolate)) {
} }
ForStatement::ForStatement(ZoneStringList* labels) ForStatement::ForStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(labels), : IterationStatement(isolate, labels),
init_(NULL), init_(NULL),
cond_(NULL), cond_(NULL),
next_(NULL), next_(NULL),
may_have_function_literal_(true), may_have_function_literal_(true),
loop_variable_(NULL), loop_variable_(NULL),
continue_id_(GetNextId()), continue_id_(GetNextId(isolate)),
body_id_(GetNextId()) { body_id_(GetNextId(isolate)) {
} }
ForInStatement::ForInStatement(ZoneStringList* labels) ForInStatement::ForInStatement(Isolate* isolate, ZoneStringList* labels)
: IterationStatement(labels), each_(NULL), enumerable_(NULL), : IterationStatement(isolate, labels),
assignment_id_(GetNextId()) { each_(NULL),
enumerable_(NULL),
assignment_id_(GetNextId(isolate)) {
} }

68
deps/v8/src/ast.cc

@ -37,11 +37,11 @@ namespace v8 {
namespace internal { namespace internal {
AstSentinels::AstSentinels() AstSentinels::AstSentinels()
: this_proxy_(true), : this_proxy_(Isolate::Current(), true),
identifier_proxy_(false), identifier_proxy_(Isolate::Current(), false),
valid_left_hand_side_sentinel_(), valid_left_hand_side_sentinel_(Isolate::Current()),
this_property_(&this_proxy_, NULL, 0), this_property_(Isolate::Current(), &this_proxy_, NULL, 0),
call_sentinel_(NULL, NULL, 0) { call_sentinel_(Isolate::Current(), NULL, NULL, 0) {
} }
@ -72,8 +72,9 @@ CountOperation* ExpressionStatement::StatementAsCountOperation() {
} }
VariableProxy::VariableProxy(Variable* var) VariableProxy::VariableProxy(Isolate* isolate, Variable* var)
: name_(var->name()), : Expression(isolate),
name_(var->name()),
var_(NULL), // Will be set by the call to BindTo. var_(NULL), // Will be set by the call to BindTo.
is_this_(var->is_this()), is_this_(var->is_this()),
inside_with_(false), inside_with_(false),
@ -83,26 +84,29 @@ VariableProxy::VariableProxy(Variable* var)
} }
VariableProxy::VariableProxy(Handle<String> name, VariableProxy::VariableProxy(Isolate* isolate,
Handle<String> name,
bool is_this, bool is_this,
bool inside_with, bool inside_with,
int position) int position)
: name_(name), : Expression(isolate),
var_(NULL), name_(name),
is_this_(is_this), var_(NULL),
inside_with_(inside_with), is_this_(is_this),
is_trivial_(false), inside_with_(inside_with),
position_(position) { is_trivial_(false),
position_(position) {
// Names must be canonicalized for fast equality checks. // Names must be canonicalized for fast equality checks.
ASSERT(name->IsSymbol()); ASSERT(name->IsSymbol());
} }
VariableProxy::VariableProxy(bool is_this) VariableProxy::VariableProxy(Isolate* isolate, bool is_this)
: var_(NULL), : Expression(isolate),
is_this_(is_this), var_(NULL),
inside_with_(false), is_this_(is_this),
is_trivial_(false) { inside_with_(false),
is_trivial_(false) {
} }
@ -120,17 +124,19 @@ void VariableProxy::BindTo(Variable* var) {
} }
Assignment::Assignment(Token::Value op, Assignment::Assignment(Isolate* isolate,
Token::Value op,
Expression* target, Expression* target,
Expression* value, Expression* value,
int pos) int pos)
: op_(op), : Expression(isolate),
op_(op),
target_(target), target_(target),
value_(value), value_(value),
pos_(pos), pos_(pos),
binary_operation_(NULL), binary_operation_(NULL),
compound_load_id_(kNoNumber), compound_load_id_(kNoNumber),
assignment_id_(GetNextId()), assignment_id_(GetNextId(isolate)),
block_start_(false), block_start_(false),
block_end_(false), block_end_(false),
is_monomorphic_(false), is_monomorphic_(false),
@ -138,8 +144,12 @@ Assignment::Assignment(Token::Value op,
ASSERT(Token::IsAssignmentOp(op)); ASSERT(Token::IsAssignmentOp(op));
if (is_compound()) { if (is_compound()) {
binary_operation_ = binary_operation_ =
new BinaryOperation(binary_op(), target, value, pos + 1); new(isolate->zone()) BinaryOperation(isolate,
compound_load_id_ = GetNextId(); binary_op(),
target,
value,
pos + 1);
compound_load_id_ = GetNextId(isolate);
} }
} }
@ -186,8 +196,9 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) {
ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) { ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
Isolate* isolate = Isolate::Current();
emit_store_ = true; emit_store_ = true;
key_ = new Literal(value->name()); key_ = new(isolate->zone()) Literal(isolate, value->name());
value_ = value; value_ = value;
kind_ = is_getter ? GETTER : SETTER; kind_ = is_getter ? GETTER : SETTER;
} }
@ -1190,15 +1201,16 @@ RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes)
} }
CaseClause::CaseClause(Expression* label, CaseClause::CaseClause(Isolate* isolate,
Expression* label,
ZoneList<Statement*>* statements, ZoneList<Statement*>* statements,
int pos) int pos)
: label_(label), : label_(label),
statements_(statements), statements_(statements),
position_(pos), position_(pos),
compare_type_(NONE), compare_type_(NONE),
compare_id_(AstNode::GetNextId()), compare_id_(AstNode::GetNextId(isolate)),
entry_id_(AstNode::GetNextId()) { entry_id_(AstNode::GetNextId(isolate)) {
} }
} } // namespace v8::internal } } // namespace v8::internal

213
deps/v8/src/ast.h

@ -134,11 +134,15 @@ 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.
AstNode() { // Override ZoneObject's new to count allocated AST nodes.
Isolate* isolate = Isolate::Current(); void* operator new(size_t size, Zone* zone) {
Isolate* isolate = zone->isolate();
isolate->set_ast_node_count(isolate->ast_node_count() + 1); isolate->set_ast_node_count(isolate->ast_node_count() + 1);
return zone->New(static_cast<int>(size));
} }
AstNode() {}
virtual ~AstNode() { } virtual ~AstNode() { }
virtual void Accept(AstVisitor* v) = 0; virtual void Accept(AstVisitor* v) = 0;
@ -165,14 +169,21 @@ class AstNode: public ZoneObject {
static void ResetIds() { Isolate::Current()->set_ast_node_id(0); } static void ResetIds() { Isolate::Current()->set_ast_node_id(0); }
protected: protected:
static unsigned GetNextId() { return ReserveIdRange(1); } static unsigned GetNextId(Isolate* isolate) {
static unsigned ReserveIdRange(int n) { return ReserveIdRange(isolate, 1);
Isolate* isolate = Isolate::Current(); }
static unsigned ReserveIdRange(Isolate* isolate, int n) {
unsigned tmp = isolate->ast_node_id(); unsigned tmp = isolate->ast_node_id();
isolate->set_ast_node_id(tmp + n); isolate->set_ast_node_id(tmp + n);
return tmp; return tmp;
} }
private:
// Hidden to prevent accidental usage. It would have to load the
// current zone from the TLS.
void* operator new(size_t size);
friend class CaseClause; // Generates AST IDs. friend class CaseClause; // Generates AST IDs.
}; };
@ -210,7 +221,9 @@ class Expression: public AstNode {
kTest kTest
}; };
Expression() : id_(GetNextId()), test_id_(GetNextId()) {} explicit Expression(Isolate* isolate)
: id_(GetNextId(isolate)),
test_id_(GetNextId(isolate)) {}
virtual int position() const { virtual int position() const {
UNREACHABLE(); UNREACHABLE();
@ -277,6 +290,7 @@ class Expression: public AstNode {
*/ */
class ValidLeftHandSideSentinel: public Expression { class ValidLeftHandSideSentinel: public Expression {
public: public:
explicit ValidLeftHandSideSentinel(Isolate* isolate) : Expression(isolate) {}
virtual bool IsValidLeftHandSide() { return true; } virtual bool IsValidLeftHandSide() { return true; }
virtual void Accept(AstVisitor* v) { UNREACHABLE(); } virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
virtual bool IsInlineable() const; virtual bool IsInlineable() const;
@ -308,7 +322,7 @@ class BreakableStatement: public Statement {
int ExitId() const { return exit_id_; } int ExitId() const { return exit_id_; }
protected: protected:
inline BreakableStatement(ZoneStringList* labels, Type type); BreakableStatement(Isolate* isolate, ZoneStringList* labels, Type type);
private: private:
ZoneStringList* labels_; ZoneStringList* labels_;
@ -321,7 +335,10 @@ class BreakableStatement: public Statement {
class Block: public BreakableStatement { class Block: public BreakableStatement {
public: public:
inline Block(ZoneStringList* labels, int capacity, bool is_initializer_block); inline Block(Isolate* isolate,
ZoneStringList* labels,
int capacity,
bool is_initializer_block);
DECLARE_NODE_TYPE(Block) DECLARE_NODE_TYPE(Block)
@ -389,7 +406,7 @@ class IterationStatement: public BreakableStatement {
Label* continue_target() { return &continue_target_; } Label* continue_target() { return &continue_target_; }
protected: protected:
explicit inline IterationStatement(ZoneStringList* labels); inline IterationStatement(Isolate* isolate, ZoneStringList* labels);
void Initialize(Statement* body) { void Initialize(Statement* body) {
body_ = body; body_ = body;
@ -404,7 +421,7 @@ class IterationStatement: public BreakableStatement {
class DoWhileStatement: public IterationStatement { class DoWhileStatement: public IterationStatement {
public: public:
explicit inline DoWhileStatement(ZoneStringList* labels); inline DoWhileStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(DoWhileStatement) DECLARE_NODE_TYPE(DoWhileStatement)
@ -437,7 +454,7 @@ class DoWhileStatement: public IterationStatement {
class WhileStatement: public IterationStatement { class WhileStatement: public IterationStatement {
public: public:
explicit inline WhileStatement(ZoneStringList* labels); inline WhileStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(WhileStatement) DECLARE_NODE_TYPE(WhileStatement)
@ -470,7 +487,7 @@ class WhileStatement: public IterationStatement {
class ForStatement: public IterationStatement { class ForStatement: public IterationStatement {
public: public:
explicit inline ForStatement(ZoneStringList* labels); inline ForStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(ForStatement) DECLARE_NODE_TYPE(ForStatement)
@ -519,7 +536,7 @@ class ForStatement: public IterationStatement {
class ForInStatement: public IterationStatement { class ForInStatement: public IterationStatement {
public: public:
explicit inline ForInStatement(ZoneStringList* labels); inline ForInStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(ForInStatement) DECLARE_NODE_TYPE(ForInStatement)
@ -636,7 +653,10 @@ class ExitContextStatement: public Statement {
class CaseClause: public ZoneObject { class CaseClause: public ZoneObject {
public: public:
CaseClause(Expression* label, ZoneList<Statement*>* statements, int pos); CaseClause(Isolate* isolate,
Expression* label,
ZoneList<Statement*>* statements,
int pos);
bool is_default() const { return label_ == NULL; } bool is_default() const { return label_ == NULL; }
Expression* label() const { Expression* label() const {
@ -671,7 +691,7 @@ class CaseClause: public ZoneObject {
class SwitchStatement: public BreakableStatement { class SwitchStatement: public BreakableStatement {
public: public:
explicit inline SwitchStatement(ZoneStringList* labels); inline SwitchStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(SwitchStatement) DECLARE_NODE_TYPE(SwitchStatement)
@ -697,15 +717,16 @@ class SwitchStatement: public BreakableStatement {
// given if-statement has a then- or an else-part containing code. // given if-statement has a then- or an else-part containing code.
class IfStatement: public Statement { class IfStatement: public Statement {
public: public:
IfStatement(Expression* condition, IfStatement(Isolate* isolate,
Expression* condition,
Statement* then_statement, Statement* then_statement,
Statement* else_statement) Statement* else_statement)
: condition_(condition), : condition_(condition),
then_statement_(then_statement), then_statement_(then_statement),
else_statement_(else_statement), else_statement_(else_statement),
if_id_(GetNextId()), if_id_(GetNextId(isolate)),
then_id_(GetNextId()), then_id_(GetNextId(isolate)),
else_id_(GetNextId()) { else_id_(GetNextId(isolate)) {
} }
DECLARE_NODE_TYPE(IfStatement) DECLARE_NODE_TYPE(IfStatement)
@ -834,7 +855,8 @@ class EmptyStatement: public Statement {
class Literal: public Expression { class Literal: public Expression {
public: public:
explicit Literal(Handle<Object> handle) : handle_(handle) { } Literal(Isolate* isolate, Handle<Object> handle)
: Expression(isolate), handle_(handle) { }
DECLARE_NODE_TYPE(Literal) DECLARE_NODE_TYPE(Literal)
@ -887,8 +909,14 @@ class Literal: public Expression {
// Base class for literals that needs space in the corresponding JSFunction. // Base class for literals that needs space in the corresponding JSFunction.
class MaterializedLiteral: public Expression { class MaterializedLiteral: public Expression {
public: public:
explicit MaterializedLiteral(int literal_index, bool is_simple, int depth) MaterializedLiteral(Isolate* isolate,
: literal_index_(literal_index), is_simple_(is_simple), depth_(depth) {} int literal_index,
bool is_simple,
int depth)
: Expression(isolate),
literal_index_(literal_index),
is_simple_(is_simple),
depth_(depth) {}
virtual MaterializedLiteral* AsMaterializedLiteral() { return this; } virtual MaterializedLiteral* AsMaterializedLiteral() { return this; }
@ -944,14 +972,15 @@ class ObjectLiteral: public MaterializedLiteral {
bool emit_store_; bool emit_store_;
}; };
ObjectLiteral(Handle<FixedArray> constant_properties, ObjectLiteral(Isolate* isolate,
Handle<FixedArray> constant_properties,
ZoneList<Property*>* properties, ZoneList<Property*>* properties,
int literal_index, int literal_index,
bool is_simple, bool is_simple,
bool fast_elements, bool fast_elements,
int depth, int depth,
bool has_function) bool has_function)
: MaterializedLiteral(literal_index, is_simple, depth), : MaterializedLiteral(isolate, literal_index, is_simple, depth),
constant_properties_(constant_properties), constant_properties_(constant_properties),
properties_(properties), properties_(properties),
fast_elements_(fast_elements), fast_elements_(fast_elements),
@ -990,10 +1019,11 @@ class ObjectLiteral: public MaterializedLiteral {
// Node for capturing a regexp literal. // Node for capturing a regexp literal.
class RegExpLiteral: public MaterializedLiteral { class RegExpLiteral: public MaterializedLiteral {
public: public:
RegExpLiteral(Handle<String> pattern, RegExpLiteral(Isolate* isolate,
Handle<String> pattern,
Handle<String> flags, Handle<String> flags,
int literal_index) int literal_index)
: MaterializedLiteral(literal_index, false, 1), : MaterializedLiteral(isolate, literal_index, false, 1),
pattern_(pattern), pattern_(pattern),
flags_(flags) {} flags_(flags) {}
@ -1011,15 +1041,16 @@ class RegExpLiteral: public MaterializedLiteral {
// for minimizing the work when constructing it at runtime. // for minimizing the work when constructing it at runtime.
class ArrayLiteral: public MaterializedLiteral { class ArrayLiteral: public MaterializedLiteral {
public: public:
ArrayLiteral(Handle<FixedArray> constant_elements, ArrayLiteral(Isolate* isolate,
Handle<FixedArray> constant_elements,
ZoneList<Expression*>* values, ZoneList<Expression*>* values,
int literal_index, int literal_index,
bool is_simple, bool is_simple,
int depth) int depth)
: MaterializedLiteral(literal_index, is_simple, depth), : MaterializedLiteral(isolate, literal_index, is_simple, depth),
constant_elements_(constant_elements), constant_elements_(constant_elements),
values_(values), values_(values),
first_element_id_(ReserveIdRange(values->length())) {} first_element_id_(ReserveIdRange(isolate, values->length())) {}
DECLARE_NODE_TYPE(ArrayLiteral) DECLARE_NODE_TYPE(ArrayLiteral)
@ -1038,7 +1069,7 @@ class ArrayLiteral: public MaterializedLiteral {
class VariableProxy: public Expression { class VariableProxy: public Expression {
public: public:
explicit VariableProxy(Variable* var); VariableProxy(Isolate* isolate, Variable* var);
DECLARE_NODE_TYPE(VariableProxy) DECLARE_NODE_TYPE(VariableProxy)
@ -1085,11 +1116,12 @@ class VariableProxy: public Expression {
bool is_trivial_; bool is_trivial_;
int position_; int position_;
VariableProxy(Handle<String> name, VariableProxy(Isolate* isolate,
Handle<String> name,
bool is_this, bool is_this,
bool inside_with, bool inside_with,
int position = RelocInfo::kNoPosition); int position = RelocInfo::kNoPosition);
explicit VariableProxy(bool is_this); VariableProxy(Isolate* isolate, bool is_this);
friend class Scope; friend class Scope;
}; };
@ -1100,7 +1132,8 @@ class VariableProxySentinel: public VariableProxy {
virtual bool IsValidLeftHandSide() { return !is_this(); } virtual bool IsValidLeftHandSide() { return !is_this(); }
private: private:
explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { } VariableProxySentinel(Isolate* isolate, bool is_this)
: VariableProxy(isolate, is_this) { }
friend class AstSentinels; friend class AstSentinels;
}; };
@ -1130,8 +1163,8 @@ class Slot: public Expression {
LOOKUP LOOKUP
}; };
Slot(Variable* var, Type type, int index) Slot(Isolate* isolate, Variable* var, Type type, int index)
: var_(var), type_(type), index_(index) { : Expression(isolate), var_(var), type_(type), index_(index) {
ASSERT(var != NULL); ASSERT(var != NULL);
} }
@ -1162,8 +1195,13 @@ class Property: public Expression {
// properties should use the global object as receiver, not the base object // properties should use the global object as receiver, not the base object
// of the resolved Reference. // of the resolved Reference.
enum Type { NORMAL, SYNTHETIC }; enum Type { NORMAL, SYNTHETIC };
Property(Expression* obj, Expression* key, int pos, Type type = NORMAL) Property(Isolate* isolate,
: obj_(obj), Expression* obj,
Expression* key,
int pos,
Type type = NORMAL)
: Expression(isolate),
obj_(obj),
key_(key), key_(key),
pos_(pos), pos_(pos),
type_(type), type_(type),
@ -1215,14 +1253,18 @@ class Property: public Expression {
class Call: public Expression { class Call: public Expression {
public: public:
Call(Expression* expression, ZoneList<Expression*>* arguments, int pos) Call(Isolate* isolate,
: expression_(expression), Expression* expression,
ZoneList<Expression*>* arguments,
int pos)
: Expression(isolate),
expression_(expression),
arguments_(arguments), arguments_(arguments),
pos_(pos), pos_(pos),
is_monomorphic_(false), is_monomorphic_(false),
check_type_(RECEIVER_MAP_CHECK), check_type_(RECEIVER_MAP_CHECK),
receiver_types_(NULL), receiver_types_(NULL),
return_id_(GetNextId()) { return_id_(GetNextId(isolate)) {
} }
DECLARE_NODE_TYPE(Call) DECLARE_NODE_TYPE(Call)
@ -1301,8 +1343,14 @@ class AstSentinels {
class CallNew: public Expression { class CallNew: public Expression {
public: public:
CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos) CallNew(Isolate* isolate,
: expression_(expression), arguments_(arguments), pos_(pos) { } Expression* expression,
ZoneList<Expression*>* arguments,
int pos)
: Expression(isolate),
expression_(expression),
arguments_(arguments),
pos_(pos) { }
DECLARE_NODE_TYPE(CallNew) DECLARE_NODE_TYPE(CallNew)
@ -1325,10 +1373,14 @@ class CallNew: public Expression {
// implemented in JavaScript (see "v8natives.js"). // implemented in JavaScript (see "v8natives.js").
class CallRuntime: public Expression { class CallRuntime: public Expression {
public: public:
CallRuntime(Handle<String> name, CallRuntime(Isolate* isolate,
Handle<String> name,
const Runtime::Function* function, const Runtime::Function* function,
ZoneList<Expression*>* arguments) ZoneList<Expression*>* arguments)
: name_(name), function_(function), arguments_(arguments) { } : Expression(isolate),
name_(name),
function_(function),
arguments_(arguments) { }
DECLARE_NODE_TYPE(CallRuntime) DECLARE_NODE_TYPE(CallRuntime)
@ -1348,8 +1400,11 @@ class CallRuntime: public Expression {
class UnaryOperation: public Expression { class UnaryOperation: public Expression {
public: public:
UnaryOperation(Token::Value op, Expression* expression, int pos) UnaryOperation(Isolate* isolate,
: op_(op), expression_(expression), pos_(pos) { Token::Value op,
Expression* expression,
int pos)
: Expression(isolate), op_(op), expression_(expression), pos_(pos) {
ASSERT(Token::IsUnaryOp(op)); ASSERT(Token::IsUnaryOp(op));
} }
@ -1372,14 +1427,15 @@ class UnaryOperation: public Expression {
class BinaryOperation: public Expression { class BinaryOperation: public Expression {
public: public:
BinaryOperation(Token::Value op, BinaryOperation(Isolate* isolate,
Token::Value op,
Expression* left, Expression* left,
Expression* right, Expression* right,
int pos) int pos)
: op_(op), left_(left), right_(right), pos_(pos) { : Expression(isolate), op_(op), left_(left), right_(right), pos_(pos) {
ASSERT(Token::IsBinaryOp(op)); ASSERT(Token::IsBinaryOp(op));
right_id_ = (op == Token::AND || op == Token::OR) right_id_ = (op == Token::AND || op == Token::OR)
? static_cast<int>(GetNextId()) ? static_cast<int>(GetNextId(isolate))
: AstNode::kNoNumber; : AstNode::kNoNumber;
} }
@ -1410,13 +1466,18 @@ class BinaryOperation: public Expression {
class CountOperation: public Expression { class CountOperation: public Expression {
public: public:
CountOperation(Token::Value op, bool is_prefix, Expression* expr, int pos) CountOperation(Isolate* isolate,
: op_(op), Token::Value op,
bool is_prefix,
Expression* expr,
int pos)
: Expression(isolate),
op_(op),
is_prefix_(is_prefix), is_prefix_(is_prefix),
expression_(expr), expression_(expr),
pos_(pos), pos_(pos),
assignment_id_(GetNextId()), assignment_id_(GetNextId(isolate)),
count_id_(GetNextId()), count_id_(GetNextId(isolate)),
receiver_types_(NULL) { } receiver_types_(NULL) { }
DECLARE_NODE_TYPE(CountOperation) DECLARE_NODE_TYPE(CountOperation)
@ -1462,11 +1523,17 @@ class CountOperation: public Expression {
class CompareOperation: public Expression { class CompareOperation: public Expression {
public: public:
CompareOperation(Token::Value op, CompareOperation(Isolate* isolate,
Token::Value op,
Expression* left, Expression* left,
Expression* right, Expression* right,
int pos) int pos)
: op_(op), left_(left), right_(right), pos_(pos), compare_type_(NONE) { : Expression(isolate),
op_(op),
left_(left),
right_(right),
pos_(pos),
compare_type_(NONE) {
ASSERT(Token::IsCompareOp(op)); ASSERT(Token::IsCompareOp(op));
} }
@ -1501,8 +1568,8 @@ class CompareOperation: public Expression {
class CompareToNull: public Expression { class CompareToNull: public Expression {
public: public:
CompareToNull(bool is_strict, Expression* expression) CompareToNull(Isolate* isolate, bool is_strict, Expression* expression)
: is_strict_(is_strict), expression_(expression) { } : Expression(isolate), is_strict_(is_strict), expression_(expression) { }
DECLARE_NODE_TYPE(CompareToNull) DECLARE_NODE_TYPE(CompareToNull)
@ -1520,18 +1587,20 @@ class CompareToNull: public Expression {
class Conditional: public Expression { class Conditional: public Expression {
public: public:
Conditional(Expression* condition, Conditional(Isolate* isolate,
Expression* condition,
Expression* then_expression, Expression* then_expression,
Expression* else_expression, Expression* else_expression,
int then_expression_position, int then_expression_position,
int else_expression_position) int else_expression_position)
: condition_(condition), : Expression(isolate),
condition_(condition),
then_expression_(then_expression), then_expression_(then_expression),
else_expression_(else_expression), else_expression_(else_expression),
then_expression_position_(then_expression_position), then_expression_position_(then_expression_position),
else_expression_position_(else_expression_position), else_expression_position_(else_expression_position),
then_id_(GetNextId()), then_id_(GetNextId(isolate)),
else_id_(GetNextId()) { else_id_(GetNextId(isolate)) {
} }
DECLARE_NODE_TYPE(Conditional) DECLARE_NODE_TYPE(Conditional)
@ -1561,7 +1630,11 @@ class Conditional: public Expression {
class Assignment: public Expression { class Assignment: public Expression {
public: public:
Assignment(Token::Value op, Expression* target, Expression* value, int pos); Assignment(Isolate* isolate,
Token::Value op,
Expression* target,
Expression* value,
int pos);
DECLARE_NODE_TYPE(Assignment) DECLARE_NODE_TYPE(Assignment)
@ -1621,8 +1694,8 @@ class Assignment: public Expression {
class Throw: public Expression { class Throw: public Expression {
public: public:
Throw(Expression* exception, int pos) Throw(Isolate* isolate, Expression* exception, int pos)
: exception_(exception), pos_(pos) {} : Expression(isolate), exception_(exception), pos_(pos) {}
DECLARE_NODE_TYPE(Throw) DECLARE_NODE_TYPE(Throw)
@ -1638,7 +1711,8 @@ class Throw: public Expression {
class FunctionLiteral: public Expression { class FunctionLiteral: public Expression {
public: public:
FunctionLiteral(Handle<String> name, FunctionLiteral(Isolate* isolate,
Handle<String> name,
Scope* scope, Scope* scope,
ZoneList<Statement*>* body, ZoneList<Statement*>* body,
int materialized_literal_count, int materialized_literal_count,
@ -1650,7 +1724,8 @@ class FunctionLiteral: public Expression {
int end_position, int end_position,
bool is_expression, bool is_expression,
bool has_duplicate_parameters) bool has_duplicate_parameters)
: name_(name), : Expression(isolate),
name_(name),
scope_(scope), scope_(scope),
body_(body), body_(body),
materialized_literal_count_(materialized_literal_count), materialized_literal_count_(materialized_literal_count),
@ -1729,9 +1804,10 @@ class FunctionLiteral: public Expression {
class SharedFunctionInfoLiteral: public Expression { class SharedFunctionInfoLiteral: public Expression {
public: public:
explicit SharedFunctionInfoLiteral( SharedFunctionInfoLiteral(
Isolate* isolate,
Handle<SharedFunctionInfo> shared_function_info) Handle<SharedFunctionInfo> shared_function_info)
: shared_function_info_(shared_function_info) { } : Expression(isolate), shared_function_info_(shared_function_info) { }
DECLARE_NODE_TYPE(SharedFunctionInfoLiteral) DECLARE_NODE_TYPE(SharedFunctionInfoLiteral)
@ -1747,6 +1823,7 @@ class SharedFunctionInfoLiteral: public Expression {
class ThisFunction: public Expression { class ThisFunction: public Expression {
public: public:
explicit ThisFunction(Isolate* isolate) : Expression(isolate) {}
DECLARE_NODE_TYPE(ThisFunction) DECLARE_NODE_TYPE(ThisFunction)
virtual bool IsInlineable() const; virtual bool IsInlineable() const;
}; };

1
deps/v8/src/bootstrapper.cc

@ -1309,6 +1309,7 @@ void Genesis::InstallNativeFunctions() {
void Genesis::InstallExperimentalNativeFunctions() { void Genesis::InstallExperimentalNativeFunctions() {
if (FLAG_harmony_proxies) { if (FLAG_harmony_proxies) {
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap); INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap); INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
} }

4
deps/v8/src/builtins.cc

@ -1202,10 +1202,10 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
ASSERT(!CalledAsConstructor(isolate)); ASSERT(!CalledAsConstructor(isolate));
Heap* heap = isolate->heap(); Heap* heap = isolate->heap();
Handle<Object> receiver = args.at<Object>(0); Handle<Object> receiver = args.receiver();
// Get the object called. // Get the object called.
JSObject* obj = JSObject::cast(*args.receiver()); JSObject* obj = JSObject::cast(*receiver);
// Get the invocation callback from the function descriptor that was // Get the invocation callback from the function descriptor that was
// used to create the called object. // used to create the called object.

5
deps/v8/src/code-stubs.cc

@ -250,7 +250,7 @@ void KeyedLoadElementStub::Generate(MacroAssembler* masm) {
KeyedLoadStubCompiler::GenerateLoadFastElement(masm); KeyedLoadStubCompiler::GenerateLoadFastElement(masm);
break; break;
case JSObject::FAST_DOUBLE_ELEMENTS: case JSObject::FAST_DOUBLE_ELEMENTS:
UNIMPLEMENTED(); KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm);
break; break;
case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
@ -279,7 +279,8 @@ void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_); KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_);
break; break;
case JSObject::FAST_DOUBLE_ELEMENTS: case JSObject::FAST_DOUBLE_ELEMENTS:
UNIMPLEMENTED(); KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
is_js_array_);
break; break;
case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_BYTE_ELEMENTS:
case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:

2
deps/v8/src/compiler.cc

@ -511,7 +511,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
info.SetPreParseData(pre_data); info.SetPreParseData(pre_data);
if (natives == NATIVES_CODE) { if (natives == NATIVES_CODE) {
info.MarkAsAllowingNativesSyntax(); info.MarkAsAllowingNativesSyntax();
info.MarkAsNative();
} }
result = MakeFunctionInfo(&info); result = MakeFunctionInfo(&info);
if (extension == NULL && !result.is_null()) { if (extension == NULL && !result.is_null()) {
@ -679,7 +678,6 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
info.SetFunction(literal); info.SetFunction(literal);
info.SetScope(literal->scope()); info.SetScope(literal->scope());
if (literal->scope()->is_strict_mode()) info.MarkAsStrictMode(); if (literal->scope()->is_strict_mode()) info.MarkAsStrictMode();
if (script->type()->value() == Script::TYPE_NATIVE) info.MarkAsNative();
LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal); LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal);
// Determine if the function can be lazily compiled. This is necessary to // Determine if the function can be lazily compiled. This is necessary to

9
deps/v8/src/compiler.h

@ -173,9 +173,12 @@ class CompilationInfo BASE_EMBEDDED {
void Initialize(Mode mode) { void Initialize(Mode mode) {
mode_ = V8::UseCrankshaft() ? mode : NONOPT; mode_ = V8::UseCrankshaft() ? mode : NONOPT;
if (!shared_info_.is_null()) { ASSERT(!script_.is_null());
if (shared_info_->strict_mode()) MarkAsStrictMode(); if (script_->type()->value() == Script::TYPE_NATIVE) {
if (shared_info_->native()) MarkAsNative(); MarkAsNative();
}
if (!shared_info_.is_null() && shared_info_->strict_mode()) {
MarkAsStrictMode();
} }
} }

2
deps/v8/src/contexts.h

@ -110,6 +110,7 @@ enum ContextLookupFlags {
V(MAP_CACHE_INDEX, Object, map_cache) \ V(MAP_CACHE_INDEX, Object, map_cache) \
V(CONTEXT_DATA_INDEX, Object, data) \ V(CONTEXT_DATA_INDEX, Object, data) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \ V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \ V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap)
@ -227,6 +228,7 @@ class Context: public FixedArray {
OUT_OF_MEMORY_INDEX, OUT_OF_MEMORY_INDEX,
CONTEXT_DATA_INDEX, CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX, ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX, DERIVED_GET_TRAP_INDEX,
DERIVED_SET_TRAP_INDEX, DERIVED_SET_TRAP_INDEX,

7
deps/v8/src/conversions-inl.h

@ -454,7 +454,6 @@ static double InternalStringToDouble(UnicodeCache* unicode_cache,
int significant_digits = 0; int significant_digits = 0;
int insignificant_digits = 0; int insignificant_digits = 0;
bool nonzero_digit_dropped = false; bool nonzero_digit_dropped = false;
bool fractional_part = false;
bool negative = false; bool negative = false;
@ -557,10 +556,8 @@ static double InternalStringToDouble(UnicodeCache* unicode_cache,
} }
} }
// We don't emit a '.', but adjust the exponent instead. // There is a fractional part. We don't emit a '.', but adjust the exponent
fractional_part = true; // instead.
// There is a fractional part.
while (*current >= '0' && *current <= '9') { while (*current >= '0' && *current <= '9') {
if (significant_digits < kMaxSignificantDigits) { if (significant_digits < kMaxSignificantDigits) {
ASSERT(buffer_pos < kBufferSize); ASSERT(buffer_pos < kBufferSize);

232
deps/v8/src/d8.cc

@ -26,33 +26,49 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef V8_SHARED
#define USING_V8_SHARED
#endif
#ifdef COMPRESS_STARTUP_DATA_BZ2 #ifdef COMPRESS_STARTUP_DATA_BZ2
#include <bzlib.h> #include <bzlib.h>
#endif #endif
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "v8.h" #ifdef USING_V8_SHARED
#include <assert.h>
#include "../include/v8-testing.h"
#endif // USING_V8_SHARED
#include "d8.h" #include "d8.h"
#ifndef USING_V8_SHARED
#include "api.h"
#include "checks.h"
#include "d8-debug.h" #include "d8-debug.h"
#include "debug.h" #include "debug.h"
#include "api.h"
#include "natives.h" #include "natives.h"
#include "platform.h" #include "platform.h"
#include "v8.h"
#endif // USING_V8_SHARED
#if !defined(_WIN32) && !defined(_WIN64) #if !defined(_WIN32) && !defined(_WIN64)
#include <unistd.h> // NOLINT #include <unistd.h> // NOLINT
#endif #endif
namespace v8 { #ifdef USING_V8_SHARED
#define ASSERT(condition) assert(condition)
#endif // USING_V8_SHARED
const char* Shell::kHistoryFileName = ".d8_history"; namespace v8 {
const char* Shell::kPrompt = "d8> ";
#ifndef USING_V8_SHARED
LineEditor *LineEditor::first_ = NULL; LineEditor *LineEditor::first_ = NULL;
const char* Shell::kHistoryFileName = ".d8_history";
LineEditor::LineEditor(Type type, const char* name) LineEditor::LineEditor(Type type, const char* name)
@ -98,17 +114,22 @@ CounterMap* Shell::counter_map_;
i::OS::MemoryMappedFile* Shell::counters_file_ = NULL; i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
CounterCollection Shell::local_counters_; CounterCollection Shell::local_counters_;
CounterCollection* Shell::counters_ = &local_counters_; CounterCollection* Shell::counters_ = &local_counters_;
i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
Persistent<Context> Shell::utility_context_; Persistent<Context> Shell::utility_context_;
#endif // USING_V8_SHARED
Persistent<Context> Shell::evaluation_context_; Persistent<Context> Shell::evaluation_context_;
i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
ShellOptions Shell::options; ShellOptions Shell::options;
const char* Shell::kPrompt = "d8> ";
#ifndef USING_V8_SHARED
bool CounterMap::Match(void* key1, void* key2) { bool CounterMap::Match(void* key1, void* key2) {
const char* name1 = reinterpret_cast<const char*>(key1); const char* name1 = reinterpret_cast<const char*>(key1);
const char* name2 = reinterpret_cast<const char*>(key2); const char* name2 = reinterpret_cast<const char*>(key2);
return strcmp(name1, name2) == 0; return strcmp(name1, name2) == 0;
} }
#endif // USING_V8_SHARED
// Converts a V8 value to a C string. // Converts a V8 value to a C string.
@ -122,17 +143,22 @@ bool Shell::ExecuteString(Handle<String> source,
Handle<Value> name, Handle<Value> name,
bool print_result, bool print_result,
bool report_exceptions) { bool report_exceptions) {
#ifndef USING_V8_SHARED
bool FLAG_debugger = i::FLAG_debugger;
#else
bool FLAG_debugger = false;
#endif // USING_V8_SHARED
HandleScope handle_scope; HandleScope handle_scope;
TryCatch try_catch; TryCatch try_catch;
options.script_executed = true; options.script_executed = true;
if (i::FLAG_debugger) { if (FLAG_debugger) {
// When debugging make exceptions appear to be uncaught. // When debugging make exceptions appear to be uncaught.
try_catch.SetVerbose(true); try_catch.SetVerbose(true);
} }
Handle<Script> script = Script::Compile(source, name); Handle<Script> script = Script::Compile(source, name);
if (script.IsEmpty()) { if (script.IsEmpty()) {
// Print errors that happened during compilation. // Print errors that happened during compilation.
if (report_exceptions && !i::FLAG_debugger) if (report_exceptions && !FLAG_debugger)
ReportException(&try_catch); ReportException(&try_catch);
return false; return false;
} else { } else {
@ -140,7 +166,7 @@ bool Shell::ExecuteString(Handle<String> source,
if (result.IsEmpty()) { if (result.IsEmpty()) {
ASSERT(try_catch.HasCaught()); ASSERT(try_catch.HasCaught());
// Print errors that happened during execution. // Print errors that happened during execution.
if (report_exceptions && !i::FLAG_debugger) if (report_exceptions && !FLAG_debugger)
ReportException(&try_catch); ReportException(&try_catch);
return false; return false;
} else { } else {
@ -161,6 +187,7 @@ bool Shell::ExecuteString(Handle<String> source,
Handle<Value> Shell::Print(const Arguments& args) { Handle<Value> Shell::Print(const Arguments& args) {
Handle<Value> val = Write(args); Handle<Value> val = Write(args);
printf("\n"); printf("\n");
fflush(stdout);
return val; return val;
} }
@ -196,15 +223,20 @@ Handle<Value> Shell::Read(const Arguments& args) {
Handle<Value> Shell::ReadLine(const Arguments& args) { Handle<Value> Shell::ReadLine(const Arguments& args) {
i::SmartPointer<char> line(i::ReadLine("")); static const int kBufferSize = 256;
if (*line == NULL) { char buffer[kBufferSize];
return Null(); Handle<String> accumulator = String::New("");
} bool linebreak;
size_t len = strlen(*line); int length;
if (len > 0 && line[len - 1] == '\n') { do { // Repeat if the line ends with an escape '\'.
--len; // fgets got an error. Just give up.
} if (fgets(buffer, kBufferSize, stdin) == NULL) return Null();
return String::New(*line, len); length = strlen(buffer);
linebreak = (length > 1 && buffer[length-2] == '\\');
if (linebreak) buffer[length-2] = '\n';
accumulator = String::Concat(accumulator, String::New(buffer, length-1));
} while (linebreak);
return accumulator;
} }
@ -236,6 +268,10 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
return ThrowException( return ThrowException(
String::New("Array constructor needs one parameter.")); String::New("Array constructor needs one parameter."));
} }
static const int kMaxLength = 0x3fffffff;
#ifndef USING_V8_SHARED
ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
#endif // USING_V8_SHARED
size_t length = 0; size_t length = 0;
if (args[0]->IsUint32()) { if (args[0]->IsUint32()) {
length = args[0]->Uint32Value(); length = args[0]->Uint32Value();
@ -244,7 +280,7 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
if (raw_length < 0) { if (raw_length < 0) {
return ThrowException(String::New("Array length must not be negative.")); return ThrowException(String::New("Array length must not be negative."));
} }
if (raw_length > i::ExternalArray::kMaxLength) { if (raw_length > kMaxLength) {
return ThrowException( return ThrowException(
String::New("Array length exceeds maximum length.")); String::New("Array length exceeds maximum length."));
} }
@ -252,7 +288,7 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args,
} else { } else {
return ThrowException(String::New("Array length must be a number.")); return ThrowException(String::New("Array length must be a number."));
} }
if (length > static_cast<size_t>(i::ExternalArray::kMaxLength)) { if (length > static_cast<size_t>(kMaxLength)) {
return ThrowException(String::New("Array length exceeds maximum length.")); return ThrowException(String::New("Array length exceeds maximum length."));
} }
void* data = calloc(length, element_size); void* data = calloc(length, element_size);
@ -332,7 +368,9 @@ Handle<Value> Shell::Yield(const Arguments& args) {
Handle<Value> Shell::Quit(const Arguments& args) { Handle<Value> Shell::Quit(const Arguments& args) {
int exit_code = args[0]->Int32Value(); int exit_code = args[0]->Int32Value();
#ifndef USING_V8_SHARED
OnExit(); OnExit();
#endif // USING_V8_SHARED
exit(exit_code); exit(exit_code);
return Undefined(); return Undefined();
} }
@ -381,6 +419,7 @@ void Shell::ReportException(v8::TryCatch* try_catch) {
} }
#ifndef USING_V8_SHARED
Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) { Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
HandleScope handle_scope; HandleScope handle_scope;
Context::Scope context_scope(utility_context_); Context::Scope context_scope(utility_context_);
@ -414,9 +453,11 @@ Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv); Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
return val; return val;
} }
#endif #endif // ENABLE_DEBUGGER_SUPPORT
#endif // USING_V8_SHARED
#ifndef USING_V8_SHARED
int32_t* Counter::Bind(const char* name, bool is_histogram) { int32_t* Counter::Bind(const char* name, bool is_histogram) {
int i; int i;
for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
@ -448,8 +489,8 @@ Counter* CounterCollection::GetNextCounter() {
void Shell::MapCounters(const char* name) { void Shell::MapCounters(const char* name) {
counters_file_ = i::OS::MemoryMappedFile::create(name, counters_file_ = i::OS::MemoryMappedFile::create(
sizeof(CounterCollection), &local_counters_); name, sizeof(CounterCollection), &local_counters_);
void* memory = (counters_file_ == NULL) ? void* memory = (counters_file_ == NULL) ?
NULL : counters_file_->memory(); NULL : counters_file_->memory();
if (memory == NULL) { if (memory == NULL) {
@ -514,6 +555,7 @@ void Shell::AddHistogramSample(void* histogram, int sample) {
counter->AddSample(sample); counter->AddSample(sample);
} }
void Shell::InstallUtilityScript() { void Shell::InstallUtilityScript() {
Locker lock; Locker lock;
HandleScope scope; HandleScope scope;
@ -532,7 +574,7 @@ void Shell::InstallUtilityScript() {
utility_context_->Global()->Set(String::New("$debug"), utility_context_->Global()->Set(String::New("$debug"),
Utils::ToLocal(js_debug)); Utils::ToLocal(js_debug));
debug->debug_context()->set_security_token(HEAP->undefined_value()); debug->debug_context()->set_security_token(HEAP->undefined_value());
#endif #endif // ENABLE_DEBUGGER_SUPPORT
// Run the d8 shell utility script in the utility context // Run the d8 shell utility script in the utility context
int source_index = i::NativesCollection<i::D8>::GetIndex("d8"); int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
@ -550,10 +592,10 @@ void Shell::InstallUtilityScript() {
// in the debugger. // in the debugger.
i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script); i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
i::Handle<i::Script> script_object = compiled_script->IsJSFunction() i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
? i::Handle<i::Script>(i::Script::cast( ? i::Handle<i::Script>(i::Script::cast(
i::JSFunction::cast(*compiled_script)->shared()->script())) i::JSFunction::cast(*compiled_script)->shared()->script()))
: i::Handle<i::Script>(i::Script::cast( : i::Handle<i::Script>(i::Script::cast(
i::SharedFunctionInfo::cast(*compiled_script)->script())); i::SharedFunctionInfo::cast(*compiled_script)->script()));
script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE)); script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
@ -561,8 +603,9 @@ void Shell::InstallUtilityScript() {
if (i::FLAG_debugger && !i::FLAG_debugger_agent) { if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
v8::Debug::SetDebugEventListener(HandleDebugEvent); v8::Debug::SetDebugEventListener(HandleDebugEvent);
} }
#endif #endif // ENABLE_DEBUGGER_SUPPORT
} }
#endif // USING_V8_SHARED
#ifdef COMPRESS_STARTUP_DATA_BZ2 #ifdef COMPRESS_STARTUP_DATA_BZ2
@ -629,9 +672,11 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
global_template->Set(String::New("lol_is_enabled"), Boolean::New(false)); global_template->Set(String::New("lol_is_enabled"), Boolean::New(false));
#endif #endif
#ifndef USING_V8_SHARED
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);
#endif // USING_V8_SHARED
return global_template; return global_template;
} }
@ -647,6 +692,7 @@ void Shell::Initialize() {
} }
#endif #endif
#ifndef USING_V8_SHARED
Shell::counter_map_ = new CounterMap(); Shell::counter_map_ = new CounterMap();
// Set up counters // Set up counters
if (i::StrLength(i::FLAG_map_counters) != 0) if (i::StrLength(i::FLAG_map_counters) != 0)
@ -656,9 +702,10 @@ void Shell::Initialize() {
V8::SetCreateHistogramFunction(CreateHistogram); V8::SetCreateHistogramFunction(CreateHistogram);
V8::SetAddHistogramSampleFunction(AddHistogramSample); V8::SetAddHistogramSampleFunction(AddHistogramSample);
} }
#endif // USING_V8_SHARED
if (options.test_shell) return; if (options.test_shell) return;
#ifndef USING_V8_SHARED
Locker lock; Locker lock;
HandleScope scope; HandleScope scope;
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
@ -669,18 +716,22 @@ void Shell::Initialize() {
if (i::FLAG_debugger_agent) { if (i::FLAG_debugger_agent) {
v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true); v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
} }
#endif #endif // ENABLE_DEBUGGER_SUPPORT
#endif // USING_V8_SHARED
} }
Persistent<Context> Shell::CreateEvaluationContext() { Persistent<Context> Shell::CreateEvaluationContext() {
#ifndef USING_V8_SHARED
// This needs to be a critical section since this is not thread-safe // This needs to be a critical section since this is not thread-safe
i::ScopedLock lock(context_mutex_); i::ScopedLock lock(context_mutex_);
#endif // USING_V8_SHARED
// Initialize the global objects // Initialize the global objects
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
Persistent<Context> context = Context::New(NULL, global_template); Persistent<Context> context = Context::New(NULL, global_template);
Context::Scope scope(context); Context::Scope scope(context);
#ifndef USING_V8_SHARED
i::JSArguments js_args = i::FLAG_js_arguments; i::JSArguments js_args = i::FLAG_js_arguments;
i::Handle<i::FixedArray> arguments_array = i::Handle<i::FixedArray> arguments_array =
FACTORY->NewFixedArray(js_args.argc()); FACTORY->NewFixedArray(js_args.argc());
@ -692,11 +743,13 @@ Persistent<Context> Shell::CreateEvaluationContext() {
i::Handle<i::JSArray> arguments_jsarray = i::Handle<i::JSArray> arguments_jsarray =
FACTORY->NewJSArrayWithElements(arguments_array); FACTORY->NewJSArrayWithElements(arguments_array);
context->Global()->Set(String::New("arguments"), context->Global()->Set(String::New("arguments"),
Utils::ToLocal(arguments_jsarray)); Utils::ToLocal(arguments_jsarray));
#endif // USING_V8_SHARED
return context; return context;
} }
#ifndef USING_V8_SHARED
void Shell::OnExit() { void Shell::OnExit() {
if (i::FLAG_dump_counters) { if (i::FLAG_dump_counters) {
printf("+----------------------------------------+-------------+\n"); printf("+----------------------------------------+-------------+\n");
@ -716,12 +769,18 @@ void Shell::OnExit() {
if (counters_file_ != NULL) if (counters_file_ != NULL)
delete counters_file_; delete counters_file_;
} }
#endif // USING_V8_SHARED
static char* ReadChars(const char* name, int* size_out) { static char* ReadChars(const char* name, int* size_out) {
// Release the V8 lock while reading files. // Release the V8 lock while reading files.
v8::Unlocker unlocker(Isolate::GetCurrent()); v8::Unlocker unlocker(Isolate::GetCurrent());
#ifndef USING_V8_SHARED
FILE* file = i::OS::FOpen(name, "rb"); FILE* file = i::OS::FOpen(name, "rb");
#else
// TODO(yangguo@chromium.org): reading from a directory hangs!
FILE* file = fopen(name, "rb");
#endif // USING_V8_SHARED
if (file == NULL) return NULL; if (file == NULL) return NULL;
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
@ -740,6 +799,7 @@ static char* ReadChars(const char* name, int* size_out) {
} }
#ifndef USING_V8_SHARED
static char* ReadToken(char* data, char token) { static char* ReadToken(char* data, char token) {
char* next = i::OS::StrChr(data, token); char* next = i::OS::StrChr(data, token);
if (next != NULL) { if (next != NULL) {
@ -759,6 +819,7 @@ static char* ReadLine(char* data) {
static char* ReadWord(char* data) { static char* ReadWord(char* data) {
return ReadToken(data, ' '); return ReadToken(data, ' ');
} }
#endif // USING_V8_SHARED
// Reads a file into a v8 string. // Reads a file into a v8 string.
@ -773,34 +834,44 @@ Handle<String> Shell::ReadFile(const char* name) {
void Shell::RunShell() { void Shell::RunShell() {
Locker locker;
Context::Scope context_scope(evaluation_context_);
HandleScope handle_scope;
Handle<String> name = String::New("(d8)");
#ifndef USING_V8_SHARED
LineEditor* editor = LineEditor::Get(); LineEditor* editor = LineEditor::Get();
printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name()); printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
if (i::FLAG_debugger) { if (i::FLAG_debugger) {
printf("JavaScript debugger enabled\n"); printf("JavaScript debugger enabled\n");
} }
editor->Open(); editor->Open();
while (true) { while (true) {
Locker locker;
HandleScope handle_scope;
Context::Scope context_scope(evaluation_context_);
i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt); i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
if (input.is_empty()) if (input.is_empty()) break;
break;
editor->AddHistory(*input); editor->AddHistory(*input);
Handle<String> name = String::New("(d8)");
ExecuteString(String::New(*input), name, true, true); ExecuteString(String::New(*input), name, true, true);
} }
editor->Close(); editor->Close();
#else
printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
static const int kBufferSize = 256;
while (true) {
char buffer[kBufferSize];
printf("%s", Shell::kPrompt);
if (fgets(buffer, kBufferSize, stdin) == NULL) break;
ExecuteString(String::New(buffer), name, true, true);
}
#endif // USING_V8_SHARED
printf("\n"); printf("\n");
} }
#ifndef USING_V8_SHARED
class ShellThread : public i::Thread { class ShellThread : public i::Thread {
public: public:
ShellThread(int no, i::Vector<const char> files) ShellThread(int no, i::Vector<const char> files)
: Thread("d8:ShellThread"), : Thread("d8:ShellThread"),
no_(no), files_(files) { } no_(no), files_(files) { }
virtual void Run(); virtual void Run();
private: private:
int no_; int no_;
@ -848,6 +919,7 @@ void ShellThread::Run() {
ptr = next_line; ptr = next_line;
} }
} }
#endif // USING_V8_SHARED
void SourceGroup::ExitShell(int exit_code) { void SourceGroup::ExitShell(int exit_code) {
@ -894,7 +966,12 @@ void SourceGroup::Execute() {
Handle<String> SourceGroup::ReadFile(const char* name) { Handle<String> SourceGroup::ReadFile(const char* name) {
#ifndef USING_V8_SHARED
FILE* file = i::OS::FOpen(name, "rb");
#else
// TODO(yangguo@chromium.org): reading from a directory hangs!
FILE* file = fopen(name, "rb"); FILE* file = fopen(name, "rb");
#endif // USING_V8_SHARED
if (file == NULL) return Handle<String>(); if (file == NULL) return Handle<String>();
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
@ -914,6 +991,7 @@ Handle<String> SourceGroup::ReadFile(const char* name) {
} }
#ifndef USING_V8_SHARED
i::Thread::Options SourceGroup::GetThreadOptions() { i::Thread::Options SourceGroup::GetThreadOptions() {
i::Thread::Options options; i::Thread::Options options;
options.name = "IsolateThread"; options.name = "IsolateThread";
@ -965,6 +1043,7 @@ void SourceGroup::WaitForThread() {
done_semaphore_->Wait(); done_semaphore_->Wait();
} }
} }
#endif // USING_V8_SHARED
bool Shell::SetOptions(int argc, char* argv[]) { bool Shell::SetOptions(int argc, char* argv[]) {
@ -986,12 +1065,26 @@ bool Shell::SetOptions(int argc, char* argv[]) {
options.test_shell = true; options.test_shell = true;
argv[i] = NULL; argv[i] = NULL;
} else if (strcmp(argv[i], "--preemption") == 0) { } else if (strcmp(argv[i], "--preemption") == 0) {
#ifdef USING_V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
#else
options.use_preemption = true; options.use_preemption = true;
argv[i] = NULL; argv[i] = NULL;
#endif // USING_V8_SHARED
} else if (strcmp(argv[i], "--no-preemption") == 0) { } else if (strcmp(argv[i], "--no-preemption") == 0) {
#ifdef USING_V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
#else
options.use_preemption = false; options.use_preemption = false;
argv[i] = NULL; argv[i] = NULL;
#endif // USING_V8_SHARED
} else if (strcmp(argv[i], "--preemption-interval") == 0) { } else if (strcmp(argv[i], "--preemption-interval") == 0) {
#ifdef USING_V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
#else
if (++i < argc) { if (++i < argc) {
argv[i-1] = NULL; argv[i-1] = NULL;
char* end = NULL; char* end = NULL;
@ -1007,15 +1100,33 @@ bool Shell::SetOptions(int argc, char* argv[]) {
printf("Missing value for --preemption-interval\n"); printf("Missing value for --preemption-interval\n");
return false; return false;
} }
#endif // USING_V8_SHARED
} else if (strcmp(argv[i], "-f") == 0) { } else if (strcmp(argv[i], "-f") == 0) {
// Ignore any -f flags for compatibility with other stand-alone // Ignore any -f flags for compatibility with other stand-alone
// JavaScript engines. // JavaScript engines.
continue; continue;
} else if (strcmp(argv[i], "--isolate") == 0) { } else if (strcmp(argv[i], "--isolate") == 0) {
#ifdef USING_V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
#endif // USING_V8_SHARED
options.num_isolates++; options.num_isolates++;
} }
#ifdef USING_V8_SHARED
else if (strcmp(argv[i], "--dump-counters") == 0) {
printf("D8 with shared library does not include counters\n");
return false;
} else if (strcmp(argv[i], "-p") == 0) {
printf("D8 with shared library does not support multi-threading\n");
return false;
} else if (strcmp(argv[i], "--debugger") == 0) {
printf("Javascript debugger not included\n");
return false;
}
#endif // USING_V8_SHARED
} }
#ifndef USING_V8_SHARED
// Run parallel threads if we are not using --isolate // Run parallel threads if we are not using --isolate
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
if (argv[i] == NULL) continue; if (argv[i] == NULL) continue;
@ -1038,6 +1149,7 @@ bool Shell::SetOptions(int argc, char* argv[]) {
options.parallel_files->Add(i::Vector<const char>(files, size)); options.parallel_files->Add(i::Vector<const char>(files, size));
} }
} }
#endif // USING_V8_SHARED
v8::V8::SetFlagsFromCommandLine(&argc, argv, true); v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
@ -1062,21 +1174,21 @@ bool Shell::SetOptions(int argc, char* argv[]) {
int Shell::RunMain(int argc, char* argv[]) { int Shell::RunMain(int argc, char* argv[]) {
#ifndef USING_V8_SHARED
i::List<i::Thread*> threads(1); i::List<i::Thread*> threads(1);
if (options.parallel_files != NULL)
{ for (int i = 0; i < options.parallel_files->length(); i++) {
if (options.parallel_files != NULL) i::Vector<const char> files = options.parallel_files->at(i);
for (int i = 0; i < options.parallel_files->length(); i++) { ShellThread* thread = new ShellThread(threads.length(), files);
i::Vector<const char> files = options.parallel_files->at(i); thread->Start();
ShellThread* thread = new ShellThread(threads.length(), files); threads.Add(thread);
thread->Start();
threads.Add(thread);
}
for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].StartExecuteInThread();
} }
for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].StartExecuteInThread();
}
#endif // USING_V8_SHARED
{ // NOLINT
Locker lock; Locker lock;
HandleScope scope; HandleScope scope;
Persistent<Context> context = CreateEvaluationContext(); Persistent<Context> context = CreateEvaluationContext();
@ -1090,14 +1202,18 @@ int Shell::RunMain(int argc, char* argv[]) {
} else { } else {
context.Dispose(); context.Dispose();
} }
#ifndef USING_V8_SHARED
// Start preemption if threads have been created and preemption is enabled. // Start preemption if threads have been created and preemption is enabled.
if (options.parallel_files != NULL if (options.parallel_files != NULL
&& threads.length() > 0 && threads.length() > 0
&& options.use_preemption) { && options.use_preemption) {
Locker::StartPreemption(options.preemption_interval); Locker::StartPreemption(options.preemption_interval);
} }
#endif // USING_V8_SHARED
} }
#ifndef USING_V8_SHARED
for (int i = 1; i < options.num_isolates; ++i) { for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].WaitForThread(); options.isolate_sources[i].WaitForThread();
} }
@ -1110,6 +1226,7 @@ int Shell::RunMain(int argc, char* argv[]) {
} }
OnExit(); OnExit();
#endif // USING_V8_SHARED
return 0; return 0;
} }
@ -1136,14 +1253,15 @@ int Shell::Main(int argc, char* argv[]) {
result = RunMain(argc, argv); result = RunMain(argc, argv);
} }
#ifdef ENABLE_DEBUGGER_SUPPORT
#if !defined(USING_V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
// Run remote debugger if requested, but never on --test // Run remote debugger if requested, but never on --test
if (i::FLAG_remote_debugger && !options.test_shell) { if (i::FLAG_remote_debugger && !options.test_shell) {
InstallUtilityScript(); InstallUtilityScript();
RunRemoteDebugger(i::FLAG_debugger_port); RunRemoteDebugger(i::FLAG_debugger_port);
return 0; return 0;
} }
#endif #endif // !USING_V8_SHARED && ENABLE_DEBUGGER_SUPPORT
// Run interactive shell if explicitly requested or if no script has been // Run interactive shell if explicitly requested or if no script has been
// executed, but never on --test // executed, but never on --test
@ -1151,7 +1269,9 @@ int Shell::Main(int argc, char* argv[]) {
if (( options.interactive_shell if (( options.interactive_shell
|| !options.script_executed ) || !options.script_executed )
&& !options.test_shell ) { && !options.test_shell ) {
#ifndef USING_V8_SHARED
InstallUtilityScript(); InstallUtilityScript();
#endif // USING_V8_SHARED
RunShell(); RunShell();
} }

27
deps/v8/src/d8.gyp

@ -26,12 +26,14 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{ {
'variables': {
'console%': '',
},
'targets': [ 'targets': [
{ {
'target_name': 'd8', 'target_name': 'd8',
'type': 'executable', 'type': 'executable',
'dependencies': [ 'dependencies': [
'd8_js2c#host',
'../tools/gyp/v8.gyp:v8', '../tools/gyp/v8.gyp:v8',
], ],
'include_dirs+': [ 'include_dirs+': [
@ -42,15 +44,24 @@
], ],
'sources': [ 'sources': [
'd8.cc', 'd8.cc',
'd8-debug.cc',
'<(SHARED_INTERMEDIATE_DIR)/d8-js.cc',
], ],
'conditions': [ 'conditions': [
[ 'OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { [ 'component!="shared_library"', {
'sources': [ 'd8-posix.cc', ] 'dependencies': [ 'd8_js2c#host', ],
}], 'sources': [ 'd8-debug.cc', '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', ],
[ 'OS=="win"', { 'conditions': [
'sources': [ 'd8-windows.cc', ] [ 'console=="readline"', {
'libraries': [ '-lreadline', ],
'sources': [ 'd8-readline.cc' ],
}],
[ '(OS=="linux" or OS=="mac" or OS=="freebsd" \
or OS=="openbsd" or OS=="solaris")', {
'sources': [ 'd8-posix.cc', ]
}],
[ 'OS=="win"', {
'sources': [ 'd8-windows.cc', ]
}],
],
}], }],
], ],
}, },

111
deps/v8/src/d8.h

@ -28,16 +28,23 @@
#ifndef V8_D8_H_ #ifndef V8_D8_H_
#define V8_D8_H_ #define V8_D8_H_
#include "allocation.h"
#ifndef USING_V8_SHARED
#include "v8.h" #include "v8.h"
#include "allocation.h"
#include "hashmap.h" #include "hashmap.h"
#else
#include "../include/v8.h"
#endif // USING_V8_SHARED
namespace v8 { namespace v8 {
#ifndef USING_V8_SHARED
namespace i = v8::internal; namespace i = v8::internal;
#endif // USING_V8_SHARED
#ifndef USING_V8_SHARED
// A single counter in a counter collection. // A single counter in a counter collection.
class Counter { class Counter {
public: public:
@ -110,17 +117,20 @@ class CounterMap {
static bool Match(void* key1, void* key2); static bool Match(void* key1, void* key2);
i::HashMap hash_map_; i::HashMap hash_map_;
}; };
#endif // USING_V8_SHARED
class SourceGroup { class SourceGroup {
public: public:
SourceGroup() SourceGroup() :
: next_semaphore_(v8::internal::OS::CreateSemaphore(0)), #ifndef USING_V8_SHARED
done_semaphore_(v8::internal::OS::CreateSemaphore(0)), next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
thread_(NULL), done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
argv_(NULL), thread_(NULL),
begin_offset_(0), #endif // USING_V8_SHARED
end_offset_(0) { } argv_(NULL),
begin_offset_(0),
end_offset_(0) { }
void Begin(char** argv, int offset) { void Begin(char** argv, int offset) {
argv_ = const_cast<const char**>(argv); argv_ = const_cast<const char**>(argv);
@ -131,6 +141,7 @@ class SourceGroup {
void Execute(); void Execute();
#ifndef USING_V8_SHARED
void StartExecuteInThread(); void StartExecuteInThread();
void WaitForThread(); void WaitForThread();
@ -154,6 +165,7 @@ class SourceGroup {
i::Semaphore* next_semaphore_; i::Semaphore* next_semaphore_;
i::Semaphore* done_semaphore_; i::Semaphore* done_semaphore_;
i::Thread* thread_; i::Thread* thread_;
#endif // USING_V8_SHARED
void ExitShell(int exit_code); void ExitShell(int exit_code);
Handle<String> ReadFile(const char* name); Handle<String> ReadFile(const char* name);
@ -166,34 +178,41 @@ class SourceGroup {
class ShellOptions { class ShellOptions {
public: public:
ShellOptions() ShellOptions() :
: script_executed(false), #ifndef USING_V8_SHARED
last_run(true), use_preemption(true),
stress_opt(false), preemption_interval(10),
stress_deopt(false), parallel_files(NULL),
interactive_shell(false), #endif // USING_V8_SHARED
test_shell(false), script_executed(false),
use_preemption(true), last_run(true),
preemption_interval(10), stress_opt(false),
num_isolates(1), stress_deopt(false),
isolate_sources(NULL), interactive_shell(false),
parallel_files(NULL) { } test_shell(false),
num_isolates(1),
isolate_sources(NULL) { }
#ifndef USING_V8_SHARED
bool use_preemption;
int preemption_interval;
i::List< i::Vector<const char> >* parallel_files;
#endif // USING_V8_SHARED
bool script_executed; bool script_executed;
bool last_run; bool last_run;
bool stress_opt; bool stress_opt;
bool stress_deopt; bool stress_deopt;
bool interactive_shell; bool interactive_shell;
bool test_shell; bool test_shell;
bool use_preemption;
int preemption_interval;
int num_isolates; int num_isolates;
SourceGroup* isolate_sources; SourceGroup* isolate_sources;
i::List< i::Vector<const char> >* parallel_files;
}; };
#ifdef USING_V8_SHARED
class Shell: public i::AllStatic { class Shell {
#else
class Shell : public i::AllStatic {
#endif // USING_V8_SHARED
public: public:
static bool ExecuteString(Handle<String> source, static bool ExecuteString(Handle<String> source,
Handle<Value> name, Handle<Value> name,
@ -201,6 +220,14 @@ class Shell: public i::AllStatic {
bool report_exceptions); bool report_exceptions);
static const char* ToCString(const v8::String::Utf8Value& value); static const char* ToCString(const v8::String::Utf8Value& value);
static void ReportException(TryCatch* try_catch); static void ReportException(TryCatch* try_catch);
static Handle<String> ReadFile(const char* name);
static Persistent<Context> CreateEvaluationContext();
static int RunMain(int argc, char* argv[]);
static int Main(int argc, char* argv[]);
#ifndef USING_V8_SHARED
static Handle<Array> GetCompletions(Handle<String> text,
Handle<String> full);
static void OnExit(); static void OnExit();
static int* LookupCounter(const char* name); static int* LookupCounter(const char* name);
static void* CreateHistogram(const char* name, static void* CreateHistogram(const char* name,
@ -209,18 +236,8 @@ class Shell: public i::AllStatic {
size_t buckets); size_t buckets);
static void AddHistogramSample(void* histogram, int sample); static void AddHistogramSample(void* histogram, int sample);
static void MapCounters(const char* name); static void MapCounters(const char* name);
static Handle<String> ReadFile(const char* name); #endif // USING_V8_SHARED
static void Initialize();
static Persistent<Context> CreateEvaluationContext();
static void InstallUtilityScript();
static void RunShell();
static bool SetOptions(int argc, char* argv[]);
static int RunScript(char* filename);
static int RunMain(int argc, char* argv[]);
static int Main(int argc, char* argv[]);
static Handle<ObjectTemplate> CreateGlobalTemplate();
static Handle<Array> GetCompletions(Handle<String> text,
Handle<String> full);
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
static Handle<Object> DebugMessageDetails(Handle<String> message); static Handle<Object> DebugMessageDetails(Handle<String> message);
static Handle<Value> DebugCommandToJSONRequest(Handle<String> command); static Handle<Value> DebugCommandToJSONRequest(Handle<String> command);
@ -283,15 +300,16 @@ class Shell: public i::AllStatic {
static Handle<Value> RemoveDirectory(const Arguments& args); static Handle<Value> RemoveDirectory(const Arguments& args);
static void AddOSMethods(Handle<ObjectTemplate> os_template); static void AddOSMethods(Handle<ObjectTemplate> os_template);
#ifndef USING_V8_SHARED
static const char* kHistoryFileName; static const char* kHistoryFileName;
#endif // USING_V8_SHARED
static const char* kPrompt; static const char* kPrompt;
static ShellOptions options; static ShellOptions options;
private: private:
static Persistent<Context> utility_context_;
static Persistent<Context> evaluation_context_; static Persistent<Context> evaluation_context_;
#ifndef USING_V8_SHARED
static Persistent<Context> utility_context_;
static CounterMap* counter_map_; static CounterMap* counter_map_;
// We statically allocate a set of local counters to be used if we // 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 // don't want to store the stats in a memory-mapped file
@ -299,7 +317,14 @@ class Shell: public i::AllStatic {
static CounterCollection* counters_; static CounterCollection* counters_;
static i::OS::MemoryMappedFile* counters_file_; static i::OS::MemoryMappedFile* counters_file_;
static i::Mutex* context_mutex_; static i::Mutex* context_mutex_;
static Counter* GetCounter(const char* name, bool is_histogram); static Counter* GetCounter(const char* name, bool is_histogram);
static void InstallUtilityScript();
#endif // USING_V8_SHARED
static void Initialize();
static void RunShell();
static bool SetOptions(int argc, char* argv[]);
static Handle<ObjectTemplate> CreateGlobalTemplate();
static Handle<Value> CreateExternalArray(const Arguments& args, static Handle<Value> CreateExternalArray(const Arguments& args,
ExternalArrayType type, ExternalArrayType type,
size_t element_size); size_t element_size);
@ -307,6 +332,7 @@ class Shell: public i::AllStatic {
}; };
#ifndef USING_V8_SHARED
class LineEditor { class LineEditor {
public: public:
enum Type { DUMB = 0, READLINE = 1 }; enum Type { DUMB = 0, READLINE = 1 };
@ -326,6 +352,7 @@ class LineEditor {
LineEditor* next_; LineEditor* next_;
static LineEditor* first_; static LineEditor* first_;
}; };
#endif // USING_V8_SHARED
} // namespace v8 } // namespace v8

14
deps/v8/src/debug.cc

@ -772,9 +772,9 @@ bool Debug::CompileDebuggerScript(int index) {
bool caught_exception = false; bool caught_exception = false;
Handle<JSFunction> function = Handle<JSFunction> function =
factory->NewFunctionFromSharedFunctionInfo(function_info, context); factory->NewFunctionFromSharedFunctionInfo(function_info, context);
Handle<Object> result =
Execution::TryCall(function, Handle<Object>(context->global()), Execution::TryCall(function, Handle<Object>(context->global()),
0, NULL, &caught_exception); 0, NULL, &caught_exception);
// Check for caught exceptions. // Check for caught exceptions.
if (caught_exception) { if (caught_exception) {
@ -1886,8 +1886,7 @@ void Debug::ClearMirrorCache() {
*function_name)); *function_name));
ASSERT(fun->IsJSFunction()); ASSERT(fun->IsJSFunction());
bool caught_exception; bool caught_exception;
Handle<Object> js_object = Execution::TryCall( Execution::TryCall(Handle<JSFunction>::cast(fun),
Handle<JSFunction>::cast(fun),
Handle<JSObject>(Debug::debug_context()->global()), Handle<JSObject>(Debug::debug_context()->global()),
0, NULL, &caught_exception); 0, NULL, &caught_exception);
} }
@ -2252,8 +2251,7 @@ void Debugger::OnAfterCompile(Handle<Script> script,
bool caught_exception = false; bool caught_exception = false;
const int argc = 1; const int argc = 1;
Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) }; Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
Handle<Object> result = Execution::TryCall( Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
Handle<JSFunction>::cast(update_script_break_points),
Isolate::Current()->js_builtins_object(), argc, argv, Isolate::Current()->js_builtins_object(), argc, argv,
&caught_exception); &caught_exception);
if (caught_exception) { if (caught_exception) {
@ -2930,7 +2928,7 @@ v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
v8::Handle<v8::Context> context = GetDebugEventContext(isolate); v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
// Isolate::context() may be NULL when "script collected" event occures. // Isolate::context() may be NULL when "script collected" event occures.
ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected); ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
return GetDebugEventContext(isolate); return context;
} }

7
deps/v8/src/factory.cc

@ -892,6 +892,13 @@ Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
} }
void Factory::BecomeJSObject(Handle<JSProxy> object) {
CALL_HEAP_FUNCTION_VOID(
isolate(),
isolate()->heap()->ReinitializeJSProxyAsJSObject(*object));
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo( Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<String> name, Handle<String> name,
int number_of_literals, int number_of_literals,

3
deps/v8/src/factory.h

@ -253,6 +253,9 @@ class Factory {
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype); Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
// Change the type of the argument into a regular JS object and reinitialize.
void BecomeJSObject(Handle<JSProxy> object);
Handle<JSFunction> NewFunction(Handle<String> name, Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype); Handle<Object> prototype);

1
deps/v8/src/frames.cc

@ -371,7 +371,6 @@ Code* StackFrame::GetSafepointData(Isolate* isolate,
unsigned* stack_slots) { unsigned* stack_slots) {
PcToCodeCache::PcToCodeCacheEntry* entry = PcToCodeCache::PcToCodeCacheEntry* entry =
isolate->pc_to_code_cache()->GetCacheEntry(pc); isolate->pc_to_code_cache()->GetCacheEntry(pc);
SafepointEntry cached_safepoint_entry = entry->safepoint_entry;
if (!entry->safepoint_entry.is_valid()) { if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code->GetSafepointEntry(pc); entry->safepoint_entry = entry->code->GetSafepointEntry(pc);
ASSERT(entry->safepoint_entry.is_valid()); ASSERT(entry->safepoint_entry.is_valid());

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

@ -686,7 +686,6 @@ FullCodeGenerator::InlineFunctionGenerator
void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) { void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments(); ZoneList<Expression*>* args = node->arguments();
Handle<String> name = node->name();
const Runtime::Function* function = node->function(); const Runtime::Function* function = node->function();
ASSERT(function != NULL); ASSERT(function != NULL);
ASSERT(function->intrinsic_type == Runtime::INLINE); ASSERT(function->intrinsic_type == Runtime::INLINE);

4
deps/v8/src/globals.h

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved. // Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -199,6 +199,8 @@ const int kDoubleSize = sizeof(double); // NOLINT
const int kIntptrSize = sizeof(intptr_t); // NOLINT const int kIntptrSize = sizeof(intptr_t); // NOLINT
const int kPointerSize = sizeof(void*); // NOLINT const int kPointerSize = sizeof(void*); // NOLINT
const int kDoubleSizeLog2 = 3;
#if V8_HOST_ARCH_64_BIT #if V8_HOST_ARCH_64_BIT
const int kPointerSizeLog2 = 3; const int kPointerSizeLog2 = 3;
const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000); const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000);

33
deps/v8/src/heap.cc

@ -3267,14 +3267,13 @@ MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize); MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
map->set_prototype(prototype); map->set_prototype(prototype);
map->set_pre_allocated_property_fields(1);
map->set_inobject_properties(1);
// Allocate the proxy object. // Allocate the proxy object.
Object* result; Object* result;
MaybeObject* maybe_result = Allocate(map, NEW_SPACE); MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result; if (!maybe_result->ToObject(&result)) return maybe_result;
JSProxy::cast(result)->set_handler(handler); JSProxy::cast(result)->set_handler(handler);
JSProxy::cast(result)->set_padding(Smi::FromInt(0));
return result; return result;
} }
@ -3414,6 +3413,36 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) {
} }
MaybeObject* Heap::ReinitializeJSProxyAsJSObject(JSProxy* object) {
// Allocate fresh map.
// TODO(rossberg): Once we optimize proxies, cache these maps.
Map* map;
MaybeObject* maybe_map_obj =
AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
// Check that the receiver has the same size as a fresh object.
ASSERT(map->instance_size() == object->map()->instance_size());
map->set_prototype(object->map()->prototype());
// Allocate the backing storage for the properties.
int prop_size = map->unused_property_fields() - map->inobject_properties();
Object* properties;
{ MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
if (!maybe_properties->ToObject(&properties)) return maybe_properties;
}
// Reset the map for the object.
object->set_map(map);
// Reinitialize the object from the constructor map.
InitializeJSObjectFromMap(JSObject::cast(object),
FixedArray::cast(properties), map);
return object;
}
MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor, MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
JSGlobalProxy* object) { JSGlobalProxy* object) {
ASSERT(constructor->has_initial_map()); ASSERT(constructor->has_initial_map());

5
deps/v8/src/heap.h

@ -441,6 +441,11 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocateJSProxy(Object* handler, MUST_USE_RESULT MaybeObject* AllocateJSProxy(Object* handler,
Object* prototype); Object* prototype);
// Reinitialize a JSProxy into an (empty) JSObject. The receiver
// must have the same size as an empty object. The object is reinitialized
// and behaves as an object that has been freshly allocated.
MUST_USE_RESULT MaybeObject* ReinitializeJSProxyAsJSObject(JSProxy* object);
// Reinitialize an JSGlobalProxy based on a constructor. The object // Reinitialize an JSGlobalProxy based on a constructor. The object
// must have the same size as objects allocated using the // must have the same size as objects allocated using the
// constructor. The object is reinitialized and behaves as an // constructor. The object is reinitialized and behaves as an

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

@ -1366,6 +1366,19 @@ bool HLoadKeyedFastElement::RequiresHoleCheck() const {
} }
void HLoadKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
elements()->PrintNameTo(stream);
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("]");
}
bool HLoadKeyedFastDoubleElement::RequiresHoleCheck() const {
return true;
}
void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) { void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream); object()->PrintNameTo(stream);
stream->Add("["); stream->Add("[");
@ -1451,6 +1464,15 @@ void HStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
} }
void HStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
elements()->PrintNameTo(stream);
stream->Add("[");
key()->PrintNameTo(stream);
stream->Add("] = ");
value()->PrintNameTo(stream);
}
void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) { void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream); object()->PrintNameTo(stream);
stream->Add("["); stream->Add("[");

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

@ -131,6 +131,7 @@ class LChunkBuilder;
V(LoadFunctionPrototype) \ V(LoadFunctionPrototype) \
V(LoadGlobalCell) \ V(LoadGlobalCell) \
V(LoadGlobalGeneric) \ V(LoadGlobalGeneric) \
V(LoadKeyedFastDoubleElement) \
V(LoadKeyedFastElement) \ V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \ V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \ V(LoadKeyedSpecializedArrayElement) \
@ -156,6 +157,7 @@ class LChunkBuilder;
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreGlobalGeneric) \ V(StoreGlobalGeneric) \
V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \ V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \ V(StoreKeyedSpecializedArrayElement) \
@ -588,9 +590,9 @@ class HValue: public ZoneObject {
// it would otherwise output what should be a minus zero as an int32 zero. // it would otherwise output what should be a minus zero as an int32 zero.
// If the operation also exists in a form that takes int32 and outputs int32 // If the operation also exists in a form that takes int32 and outputs int32
// then the operation should return its input value so that we can propagate // then the operation should return its input value so that we can propagate
// back. There are two operations that need to propagate back to more than // back. There are three operations that need to propagate back to more than
// one input. They are phi and binary add. They always return NULL and // one input. They are phi and binary div and mul. They always return NULL
// expect the caller to take care of things. // and expect the caller to take care of things.
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) { virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id()); visited->Add(id());
return NULL; return NULL;
@ -1123,40 +1125,19 @@ class HChange: public HUnaryOperation {
class HClampToUint8: public HUnaryOperation { class HClampToUint8: public HUnaryOperation {
public: public:
explicit HClampToUint8(HValue* value) explicit HClampToUint8(HValue* value)
: HUnaryOperation(value), : HUnaryOperation(value) {
input_rep_(Representation::None()) { set_representation(Representation::Integer32());
SetFlag(kFlexibleRepresentation);
set_representation(Representation::Tagged());
SetFlag(kUseGVN); SetFlag(kUseGVN);
} }
virtual Representation RequiredInputRepresentation(int index) const { virtual Representation RequiredInputRepresentation(int index) const {
return input_rep_; return Representation::None();
}
virtual Representation InferredRepresentation() {
// TODO(danno): Inference on input types should happen separately from
// return representation.
Representation new_rep = value()->representation();
if (input_rep_.IsNone()) {
if (!new_rep.IsNone()) {
input_rep_ = new_rep;
return Representation::Integer32();
} else {
return Representation::None();
}
} else {
return Representation::Integer32();
}
} }
DECLARE_CONCRETE_INSTRUCTION(ClampToUint8) DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
protected: protected:
virtual bool DataEquals(HValue* other) { return true; } virtual bool DataEquals(HValue* other) { return true; }
private:
Representation input_rep_;
}; };
@ -3540,6 +3521,37 @@ class HLoadKeyedFastElement: public HTemplateInstruction<2> {
}; };
class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
public:
HLoadKeyedFastDoubleElement(HValue* elements, HValue* key) {
SetOperandAt(0, elements);
SetOperandAt(1, key);
set_representation(Representation::Double());
SetFlag(kDependsOnArrayElements);
SetFlag(kUseGVN);
}
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
virtual Representation RequiredInputRepresentation(int index) const {
// The key is supposed to be Integer32.
return index == 0
? Representation::Tagged()
: Representation::Integer32();
}
virtual void PrintDataTo(StringStream* stream);
bool RequiresHoleCheck() const;
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement)
protected:
virtual bool DataEquals(HValue* other) { return true; }
};
class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> { class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
public: public:
HLoadKeyedSpecializedArrayElement(HValue* external_elements, HLoadKeyedSpecializedArrayElement(HValue* external_elements,
@ -3725,6 +3737,41 @@ class HStoreKeyedFastElement: public HTemplateInstruction<3> {
}; };
class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
public:
HStoreKeyedFastDoubleElement(HValue* elements,
HValue* key,
HValue* val) {
SetOperandAt(0, elements);
SetOperandAt(1, key);
SetOperandAt(2, val);
SetFlag(kChangesArrayElements);
}
virtual Representation RequiredInputRepresentation(int index) const {
if (index == 1) {
return Representation::Integer32();
} else if (index == 2) {
return Representation::Double();
} else {
return Representation::Tagged();
}
}
HValue* elements() { return OperandAt(0); }
HValue* key() { return OperandAt(1); }
HValue* value() { return OperandAt(2); }
bool NeedsWriteBarrier() {
return StoringValueNeedsWriteBarrier(value());
}
virtual void PrintDataTo(StringStream* stream);
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
};
class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> { class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
public: public:
HStoreKeyedSpecializedArrayElement(HValue* external_elements, HStoreKeyedSpecializedArrayElement(HValue* external_elements,

86
deps/v8/src/hydrogen.cc

@ -1666,8 +1666,8 @@ void HInferRepresentation::Analyze() {
HValue* use = it.value(); HValue* use = it.value();
if (use->IsPhi()) { if (use->IsPhi()) {
int id = HPhi::cast(use)->phi_id(); int id = HPhi::cast(use)->phi_id();
change = change || if (connected_phis[i]->UnionIsChanged(*connected_phis[id]))
connected_phis[i]->UnionIsChanged(*connected_phis[id]); change = true;
} }
} }
} }
@ -3901,7 +3901,9 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
bool is_store) { bool is_store) {
ASSERT(expr->IsMonomorphic()); ASSERT(expr->IsMonomorphic());
Handle<Map> map = expr->GetMonomorphicReceiverType(); Handle<Map> map = expr->GetMonomorphicReceiverType();
if (!map->has_fast_elements() && !map->has_external_array_elements()) { if (!map->has_fast_elements() &&
!map->has_fast_double_elements() &&
!map->has_external_array_elements()) {
return is_store ? BuildStoreKeyedGeneric(object, key, val) return is_store ? BuildStoreKeyedGeneric(object, key, val)
: BuildLoadKeyedGeneric(object, key); : BuildLoadKeyedGeneric(object, key);
} }
@ -3920,20 +3922,39 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
return BuildExternalArrayElementAccess(external_elements, checked_key, return BuildExternalArrayElementAccess(external_elements, checked_key,
val, map->elements_kind(), is_store); val, map->elements_kind(), is_store);
} }
ASSERT(map->has_fast_elements()); bool fast_double_elements = map->has_fast_double_elements();
ASSERT(map->has_fast_elements() || fast_double_elements);
if (map->instance_type() == JS_ARRAY_TYPE) { if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object)); length = AddInstruction(new(zone()) HJSArrayLength(object));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
AddInstruction(elements); AddInstruction(elements);
if (is_store && !fast_double_elements) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
}
} else { } else {
AddInstruction(elements); AddInstruction(elements);
if (is_store && !fast_double_elements) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
}
length = AddInstruction(new(zone()) HFixedArrayLength(elements)); length = AddInstruction(new(zone()) HFixedArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
} }
if (is_store) { if (is_store) {
return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); if (fast_double_elements) {
return new(zone()) HStoreKeyedFastDoubleElement(elements,
checked_key,
val);
} else {
return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
}
} else { } else {
return new(zone()) HLoadKeyedFastElement(elements, checked_key); if (fast_double_elements) {
return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
} else {
return new(zone()) HLoadKeyedFastElement(elements, checked_key);
}
} }
} }
@ -3966,8 +3987,6 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
todo_external_array = true; todo_external_array = true;
} }
} }
// Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt.
type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false;
HBasicBlock* join = graph()->CreateBasicBlock(); HBasicBlock* join = graph()->CreateBasicBlock();
@ -4016,7 +4035,8 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
set_current_block(if_true); set_current_block(if_true);
HInstruction* access; HInstruction* access;
if (elements_kind == JSObject::FAST_ELEMENTS) { if (elements_kind == JSObject::FAST_ELEMENTS ||
elements_kind == JSObject::FAST_DOUBLE_ELEMENTS) {
HBasicBlock* if_jsarray = graph()->CreateBasicBlock(); HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
HBasicBlock* if_fastobject = graph()->CreateBasicBlock(); HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
HHasInstanceTypeAndBranch* typecheck = HHasInstanceTypeAndBranch* typecheck =
@ -4032,12 +4052,28 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
elements = AddInstruction(new(zone()) HLoadElements(object)); elements = AddInstruction(new(zone()) HLoadElements(object));
elements->ClearFlag(HValue::kUseGVN); elements->ClearFlag(HValue::kUseGVN);
bool fast_double_elements =
elements_kind == JSObject::FAST_DOUBLE_ELEMENTS;
if (is_store) { if (is_store) {
access = AddInstruction( if (fast_double_elements) {
new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); access = AddInstruction(
new(zone()) HStoreKeyedFastDoubleElement(elements,
checked_key,
val));
} else {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
access = AddInstruction(
new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
}
} else { } else {
access = AddInstruction( if (fast_double_elements) {
new(zone()) HLoadKeyedFastElement(elements, checked_key)); access = AddInstruction(
new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
} else {
access = AddInstruction(
new(zone()) HLoadKeyedFastElement(elements, checked_key));
}
Push(access); Push(access);
} }
*has_side_effects |= access->HasSideEffects(); *has_side_effects |= access->HasSideEffects();
@ -4049,14 +4085,30 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
set_current_block(if_fastobject); set_current_block(if_fastobject);
elements = AddInstruction(new(zone()) HLoadElements(object)); elements = AddInstruction(new(zone()) HLoadElements(object));
elements->ClearFlag(HValue::kUseGVN); elements->ClearFlag(HValue::kUseGVN);
if (is_store && !fast_double_elements) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
}
length = AddInstruction(new(zone()) HFixedArrayLength(elements)); length = AddInstruction(new(zone()) HFixedArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) { if (is_store) {
access = AddInstruction( if (fast_double_elements) {
new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); access = AddInstruction(
new(zone()) HStoreKeyedFastDoubleElement(elements,
checked_key,
val));
} else {
access = AddInstruction(
new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
}
} else { } else {
access = AddInstruction( if (fast_double_elements) {
new(zone()) HLoadKeyedFastElement(elements, checked_key)); access = AddInstruction(
new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
} else {
access = AddInstruction(
new(zone()) HLoadKeyedFastElement(elements, checked_key));
}
} }
} else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) { } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) {
if (is_store) { if (is_store) {

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

@ -4158,6 +4158,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor = Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
__ SetCallKind(ecx, CALL_AS_METHOD);
__ jmp(adaptor, RelocInfo::CODE_TARGET); __ jmp(adaptor, RelocInfo::CODE_TARGET);
} }

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

@ -2230,10 +2230,34 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
} }
Operand LCodeGen::BuildExternalArrayOperand( void LCodeGen::DoLoadKeyedFastDoubleElement(
LLoadKeyedFastDoubleElement* instr) {
Register elements = ToRegister(instr->elements());
XMMRegister result = ToDoubleRegister(instr->result());
if (instr->hydrogen()->RequiresHoleCheck()) {
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(), instr->key(),
JSObject::FAST_DOUBLE_ELEMENTS,
offset);
__ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
}
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movdbl(result, double_load_operand);
}
Operand LCodeGen::BuildFastArrayOperand(
LOperand* external_pointer, LOperand* external_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind) { JSObject::ElementsKind elements_kind,
uint32_t offset) {
Register external_pointer_reg = ToRegister(external_pointer); Register external_pointer_reg = ToRegister(external_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind); int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) { if (key->IsConstantOperand()) {
@ -2241,10 +2265,11 @@ Operand LCodeGen::BuildExternalArrayOperand(
if (constant_value & 0xF0000000) { if (constant_value & 0xF0000000) {
Abort("array index constant value too big"); Abort("array index constant value too big");
} }
return Operand(external_pointer_reg, constant_value * (1 << shift_size)); return Operand(external_pointer_reg,
constant_value * (1 << shift_size) + offset);
} else { } else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0); return Operand(external_pointer_reg, ToRegister(key), scale_factor, offset);
} }
} }
@ -2252,8 +2277,8 @@ Operand LCodeGen::BuildExternalArrayOperand(
void LCodeGen::DoLoadKeyedSpecializedArrayElement( void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) { LLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind(); JSObject::ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildExternalArrayOperand(instr->external_pointer(), Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind)); instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result())); XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand); __ movss(result, operand);
@ -2790,7 +2815,8 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
__ ucomisd(input_reg, xmm0); __ ucomisd(input_reg, xmm0);
__ j(above, &positive, Label::kNear); __ j(above, &positive, Label::kNear);
__ j(equal, &zero, Label::kNear); __ j(equal, &zero, Label::kNear);
ExternalReference nan = ExternalReference::address_of_nan(); ExternalReference nan =
ExternalReference::address_of_canonical_non_hole_nan();
__ movdbl(input_reg, Operand::StaticVariable(nan)); __ movdbl(input_reg, Operand::StaticVariable(nan));
__ jmp(&done, Label::kNear); __ jmp(&done, Label::kNear);
__ bind(&zero); __ bind(&zero);
@ -3000,8 +3026,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
void LCodeGen::DoStoreKeyedSpecializedArrayElement( void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) { LStoreKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind(); JSObject::ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildExternalArrayOperand(instr->external_pointer(), Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind)); instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value())); __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(operand, xmm0); __ movss(operand, xmm0);
@ -3068,6 +3094,28 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
} }
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
Register elements = ToRegister(instr->elements());
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
Label have_value;
__ ucomisd(value, value);
__ j(parity_odd, &have_value); // NaN.
ExternalReference canonical_nan_reference =
ExternalReference::address_of_canonical_non_hole_nan();
__ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
__ bind(&have_value);
Operand double_store_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movdbl(double_store_operand, value);
}
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx)); ASSERT(ToRegister(instr->object()).is(edx));
@ -3451,7 +3499,8 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
DeoptimizeIf(not_equal, env); DeoptimizeIf(not_equal, env);
// Convert undefined to NaN. // Convert undefined to NaN.
ExternalReference nan = ExternalReference::address_of_nan(); ExternalReference nan =
ExternalReference::address_of_canonical_non_hole_nan();
__ movdbl(result_reg, Operand::StaticVariable(nan)); __ movdbl(result_reg, Operand::StaticVariable(nan));
__ jmp(&done, Label::kNear); __ jmp(&done, Label::kNear);

7
deps/v8/src/ia32/lithium-codegen-ia32.h

@ -222,9 +222,10 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const; Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const; XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const; int ToInteger32(LConstantOperand* op) const;
Operand BuildExternalArrayOperand(LOperand* external_pointer, Operand BuildFastArrayOperand(LOperand* external_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind); JSObject::ElementsKind elements_kind,
uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation. // Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr); void EmitIntegerMathAbs(LUnaryMathOperation* instr);

35
deps/v8/src/ia32/lithium-ia32.cc

@ -429,6 +429,15 @@ void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
} }
void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
elements()->PrintTo(stream);
stream->Add("[");
key()->PrintTo(stream);
stream->Add("] <- ");
value()->PrintTo(stream);
}
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) { void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream); object()->PrintTo(stream);
stream->Add("["); stream->Add("[");
@ -1878,6 +1887,18 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
} }
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
HLoadKeyedFastDoubleElement* instr) {
ASSERT(instr->representation().IsDouble());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastDoubleElement* result =
new LLoadKeyedFastDoubleElement(elements, key);
return AssignEnvironment(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) { HLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind(); JSObject::ElementsKind elements_kind = instr->elements_kind();
@ -1933,6 +1954,20 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
} }
LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
HStoreKeyedFastDoubleElement* instr) {
ASSERT(instr->value()->representation().IsDouble());
ASSERT(instr->elements()->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* val = UseTempRegister(instr->value());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new LStoreKeyedFastDoubleElement(elements, key, val);
}
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) { HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation()); Representation representation(instr->value()->representation());

41
deps/v8/src/ia32/lithium-ia32.h

@ -116,6 +116,7 @@ class LCodeGen;
V(LoadGlobalCell) \ V(LoadGlobalCell) \
V(LoadGlobalGeneric) \ V(LoadGlobalGeneric) \
V(LoadKeyedFastElement) \ V(LoadKeyedFastElement) \
V(LoadKeyedFastDoubleElement) \
V(LoadKeyedGeneric) \ V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \ V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \ V(LoadNamedField) \
@ -141,6 +142,7 @@ class LCodeGen;
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreGlobalGeneric) \ V(StoreGlobalGeneric) \
V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \ V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \ V(StoreKeyedSpecializedArrayElement) \
@ -1161,6 +1163,23 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
}; };
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedFastDoubleElement(LOperand* elements,
LOperand* key) {
inputs_[0] = elements;
inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
"load-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
@ -1651,6 +1670,28 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
}; };
class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyedFastDoubleElement(LOperand* elements,
LOperand* key,
LOperand* val) {
inputs_[0] = elements;
inputs_[1] = key;
inputs_[2] = val;
}
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
"store-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
virtual void PrintDataTo(StringStream* stream);
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
};
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public: public:
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,

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

@ -2043,6 +2043,9 @@ void MacroAssembler::AssertFastElements(Register elements) {
cmp(FieldOperand(elements, HeapObject::kMapOffset), cmp(FieldOperand(elements, HeapObject::kMapOffset),
Immediate(factory->fixed_array_map())); Immediate(factory->fixed_array_map()));
j(equal, &ok); j(equal, &ok);
cmp(FieldOperand(elements, HeapObject::kMapOffset),
Immediate(factory->fixed_double_array_map()));
j(equal, &ok);
cmp(FieldOperand(elements, HeapObject::kMapOffset), cmp(FieldOperand(elements, HeapObject::kMapOffset),
Immediate(factory->fixed_cow_array_map())); Immediate(factory->fixed_cow_array_map()));
j(equal, &ok); j(equal, &ok);

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

@ -3790,6 +3790,71 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
} }
void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss_force_generic, slow_allocate_heapnumber;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ JumpIfNotSmi(eax, &miss_force_generic);
// Get the elements array.
__ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
__ AssertFastElements(ecx);
// Check that the key is within bounds.
__ cmp(eax, FieldOperand(ecx, FixedDoubleArray::kLengthOffset));
__ j(above_equal, &miss_force_generic);
// Check for the hole
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
__ cmp(FieldOperand(ecx, eax, times_4, offset), Immediate(kHoleNanUpper32));
__ j(equal, &miss_force_generic);
// Always allocate a heap number for the result.
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ movdbl(xmm0, FieldOperand(ecx, eax, times_4,
FixedDoubleArray::kHeaderSize));
} else {
__ fld_d(FieldOperand(ecx, eax, times_4, FixedDoubleArray::kHeaderSize));
}
__ AllocateHeapNumber(ecx, ebx, edi, &slow_allocate_heapnumber);
// Set the value.
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0);
} else {
__ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset));
}
__ mov(eax, ecx);
__ ret(0);
__ bind(&slow_allocate_heapnumber);
// A value was pushed on the floating point stack before the allocation, if
// the allocation fails it needs to be removed.
if (!CpuFeatures::IsSupported(SSE2)) {
__ ffree();
__ fincstp();
}
Handle<Code> slow_ic =
masm->isolate()->builtins()->KeyedLoadIC_Slow();
__ jmp(slow_ic, RelocInfo::CODE_TARGET);
__ bind(&miss_force_generic);
Handle<Code> miss_ic =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
__ jmp(miss_ic, RelocInfo::CODE_TARGET);
}
void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array) { bool is_js_array) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
@ -3839,6 +3904,98 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
} }
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
MacroAssembler* masm,
bool is_js_array) {
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : key
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
Label miss_force_generic, smi_value, is_nan, maybe_nan;
Label have_double_value, not_nan;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ JumpIfNotSmi(ecx, &miss_force_generic);
// Get the elements array.
__ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
__ AssertFastElements(edi);
if (is_js_array) {
// Check that the key is within bounds.
__ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
} else {
// Check that the key is within bounds.
__ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis.
}
__ j(above_equal, &miss_force_generic);
__ JumpIfSmi(eax, &smi_value, Label::kNear);
__ CheckMap(eax,
masm->isolate()->factory()->heap_number_map(),
&miss_force_generic,
DONT_DO_SMI_CHECK);
// Double value, canonicalize NaN.
uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
__ cmp(FieldOperand(eax, offset), Immediate(kNaNOrInfinityLowerBoundUpper32));
__ j(greater_equal, &maybe_nan, Label::kNear);
__ bind(&not_nan);
ExternalReference canonical_nan_reference =
ExternalReference::address_of_canonical_non_hole_nan();
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
__ bind(&have_double_value);
__ movdbl(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize),
xmm0);
__ ret(0);
} else {
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ bind(&have_double_value);
__ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize));
__ ret(0);
}
__ bind(&maybe_nan);
// Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
// it's an Infinity, and the non-NaN code path applies.
__ j(greater, &is_nan, Label::kNear);
__ cmp(FieldOperand(eax, HeapNumber::kValueOffset), Immediate(0));
__ j(zero, &not_nan);
__ bind(&is_nan);
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatures::Scope use_sse2(SSE2);
__ movdbl(xmm0, Operand::StaticVariable(canonical_nan_reference));
} else {
__ fld_d(Operand::StaticVariable(canonical_nan_reference));
}
__ jmp(&have_double_value, Label::kNear);
__ bind(&smi_value);
// Value is a smi. convert to a double and store.
__ SmiUntag(eax);
__ push(eax);
__ fild_s(Operand(esp, 0));
__ pop(eax);
__ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize));
__ ret(0);
// Handle store cache miss, replacing the ic with the generic stub.
__ bind(&miss_force_generic);
Handle<Code> ic_force_generic =
masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
__ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

8
deps/v8/src/jsregexp.cc

@ -1,4 +1,4 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved. // Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
@ -1958,13 +1958,10 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details,
ASSERT(characters_filled_in < details->characters()); ASSERT(characters_filled_in < details->characters());
int characters = details->characters(); int characters = details->characters();
int char_mask; int char_mask;
int char_shift;
if (compiler->ascii()) { if (compiler->ascii()) {
char_mask = String::kMaxAsciiCharCode; char_mask = String::kMaxAsciiCharCode;
char_shift = 8;
} else { } else {
char_mask = String::kMaxUC16CharCode; char_mask = String::kMaxUC16CharCode;
char_shift = 16;
} }
for (int k = 0; k < elms_->length(); k++) { for (int k = 0; k < elms_->length(); k++) {
TextElement elm = elms_->at(k); TextElement elm = elms_->at(k);
@ -4888,7 +4885,6 @@ void TextNode::CalculateOffsets() {
cp_offset += elm.data.u_atom->data().length(); cp_offset += elm.data.u_atom->data().length();
} else { } else {
cp_offset++; cp_offset++;
Vector<const uc16> quarks = elm.data.u_atom->data();
} }
} }
} }
@ -5327,8 +5323,6 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
return CompilationResult(error_message); return CompilationResult(error_message);
} }
NodeInfo info = *node->info();
// Create the correct assembler for the architecture. // Create the correct assembler for the architecture.
#ifndef V8_INTERPRETED_REGEXP #ifndef V8_INTERPRETED_REGEXP
// Native regexp implementation. // Native regexp implementation.

19
deps/v8/src/messages.js

@ -195,7 +195,8 @@ function FormatMessage(message) {
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_failed: ["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"],
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"],
@ -1050,13 +1051,15 @@ function captureStackTrace(obj, cons_opt) {
$Math.__proto__ = global.Object.prototype; $Math.__proto__ = global.Object.prototype;
DefineError(function Error() { }); // DefineError is a native function. Use explicit receiver. Otherwise
DefineError(function TypeError() { }); // the receiver will be 'undefined'.
DefineError(function RangeError() { }); this.DefineError(function Error() { });
DefineError(function SyntaxError() { }); this.DefineError(function TypeError() { });
DefineError(function ReferenceError() { }); this.DefineError(function RangeError() { });
DefineError(function EvalError() { }); this.DefineError(function SyntaxError() { });
DefineError(function URIError() { }); this.DefineError(function ReferenceError() { });
this.DefineError(function EvalError() { });
this.DefineError(function URIError() { });
$Error.captureStackTrace = captureStackTrace; $Error.captureStackTrace = captureStackTrace;

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

@ -285,7 +285,7 @@ Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size)
unbound_labels_count_ = 0; unbound_labels_count_ = 0;
block_buffer_growth_ = false; block_buffer_growth_ = false;
ast_id_for_reloc_info_ = kNoASTId; ClearRecordedAstId();
} }
@ -1947,9 +1947,8 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
} }
ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here. ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
ASSERT(ast_id_for_reloc_info_ != kNoASTId); RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId());
RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_); ClearRecordedAstId();
ast_id_for_reloc_info_ = kNoASTId;
reloc_info_writer.Write(&reloc_info_with_ast_id); reloc_info_writer.Write(&reloc_info_with_ast_id);
} else { } else {
reloc_info_writer.Write(&rinfo); reloc_info_writer.Write(&rinfo);

14
deps/v8/src/mips/assembler-mips.h

@ -833,7 +833,17 @@ class Assembler : public AssemblerBase {
// Record the AST id of the CallIC being compiled, so that it can be placed // Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information. // in the relocation information.
void RecordAstId(unsigned ast_id) { ast_id_for_reloc_info_ = ast_id; } void SetRecordedAstId(unsigned ast_id) {
ASSERT(recorded_ast_id_ == kNoASTId);
recorded_ast_id_ = ast_id;
}
unsigned RecordedAstId() {
ASSERT(recorded_ast_id_ != kNoASTId);
return recorded_ast_id_;
}
void ClearRecordedAstId() { recorded_ast_id_ = kNoASTId; }
// Record a comment relocation entry that can be used by a disassembler. // Record a comment relocation entry that can be used by a disassembler.
// Use --code-comments to enable. // Use --code-comments to enable.
@ -926,7 +936,7 @@ class Assembler : public AssemblerBase {
// Relocation for a type-recording IC has the AST id added to it. This // Relocation for a type-recording IC has the AST id added to it. This
// member variable is a way to pass the information from the call site to // member variable is a way to pass the information from the call site to
// the relocation info. // the relocation info.
unsigned ast_id_for_reloc_info_; unsigned recorded_ast_id_;
bool emit_debug_code() const { return emit_debug_code_; } bool emit_debug_code() const { return emit_debug_code_; }

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

@ -4913,6 +4913,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ li(a0, Operand(argc_)); // Setup the number of arguments. __ li(a0, Operand(argc_)); // Setup the number of arguments.
__ mov(a2, zero_reg); __ mov(a2, zero_reg);
__ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION); __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(t1, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} }

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

@ -2080,8 +2080,7 @@ void MacroAssembler::Call(Handle<Code> code,
bind(&start); bind(&start);
ASSERT(RelocInfo::IsCodeTarget(rmode)); ASSERT(RelocInfo::IsCodeTarget(rmode));
if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) { if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
ASSERT(ast_id_for_reloc_info_ == kNoASTId); SetRecordedAstId(ast_id);
ast_id_for_reloc_info_ = ast_id;
rmode = RelocInfo::CODE_TARGET_WITH_ID; rmode = RelocInfo::CODE_TARGET_WITH_ID;
} }
Call(reinterpret_cast<Address>(code.location()), rmode, cond, rs, rt, bd); Call(reinterpret_cast<Address>(code.location()), rmode, cond, rs, rt, bd);
@ -3701,6 +3700,8 @@ void MacroAssembler::AssertFastElements(Register elements) {
lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
LoadRoot(at, Heap::kFixedArrayMapRootIndex); LoadRoot(at, Heap::kFixedArrayMapRootIndex);
Branch(&ok, eq, elements, Operand(at)); Branch(&ok, eq, elements, Operand(at));
LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
Branch(&ok, eq, elements, Operand(at));
LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex);
Branch(&ok, eq, elements, Operand(at)); Branch(&ok, eq, elements, Operand(at));
Abort("JSObject with fast elements map has slow elements"); Abort("JSObject with fast elements map has slow elements");

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

@ -4229,6 +4229,75 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
} }
void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
// -- a1 : receiver
// -----------------------------------
Label miss_force_generic, slow_allocate_heapnumber;
Register key_reg = a0;
Register receiver_reg = a1;
Register elements_reg = a2;
Register heap_number_reg = a2;
Register indexed_double_offset = a3;
Register scratch = t0;
Register scratch2 = t1;
Register scratch3 = t2;
Register heap_number_map = t3;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ JumpIfNotSmi(key_reg, &miss_force_generic);
// Get the elements array.
__ lw(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
// Check that the key is within bounds.
__ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
__ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
// Load the upper word of the double in the fixed array and test for NaN.
__ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
__ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
__ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
__ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
// Non-NaN. Allocate a new heap number and copy the double value into it.
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
__ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
heap_number_map, &slow_allocate_heapnumber);
// Don't need to reload the upper 32 bits of the double, it's already in
// scratch.
__ sw(scratch, FieldMemOperand(heap_number_reg,
HeapNumber::kExponentOffset));
__ lw(scratch, FieldMemOperand(indexed_double_offset,
FixedArray::kHeaderSize));
__ sw(scratch, FieldMemOperand(heap_number_reg,
HeapNumber::kMantissaOffset));
__ mov(v0, heap_number_reg);
__ Ret();
__ bind(&slow_allocate_heapnumber);
Handle<Code> slow_ic =
masm->isolate()->builtins()->KeyedLoadIC_Slow();
__ Jump(slow_ic, RelocInfo::CODE_TARGET);
__ bind(&miss_force_generic);
Handle<Code> miss_ic =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
__ Jump(miss_ic, RelocInfo::CODE_TARGET);
}
void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array) { bool is_js_array) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
@ -4292,6 +4361,126 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
} }
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
MacroAssembler* masm,
bool is_js_array) {
// ----------- S t a t e -------------
// -- a0 : value
// -- a1 : key
// -- a2 : receiver
// -- ra : return address
// -- a3 : scratch
// -- t0 : scratch (elements_reg)
// -- t1 : scratch (mantissa_reg)
// -- t2 : scratch (exponent_reg)
// -- t3 : scratch4
// -----------------------------------
Label miss_force_generic, smi_value, is_nan, maybe_nan, have_double_value;
Register value_reg = a0;
Register key_reg = a1;
Register receiver_reg = a2;
Register scratch = a3;
Register elements_reg = t0;
Register mantissa_reg = t1;
Register exponent_reg = t2;
Register scratch4 = t3;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
__ JumpIfNotSmi(key_reg, &miss_force_generic);
__ lw(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
// Check that the key is within bounds.
if (is_js_array) {
__ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
} else {
__ lw(scratch,
FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
}
// Compare smis, unsigned compare catches both negative and out-of-bound
// indexes.
__ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
// Handle smi values specially.
__ JumpIfSmi(value_reg, &smi_value);
// Ensure that the object is a heap number
__ CheckMap(value_reg,
scratch,
masm->isolate()->factory()->heap_number_map(),
&miss_force_generic,
DONT_DO_SMI_CHECK);
// Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
// in the exponent.
__ li(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
__ lw(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
__ Branch(&maybe_nan, ge, exponent_reg, Operand(scratch));
__ lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
__ bind(&have_double_value);
__ sll(scratch4, key_reg, kDoubleSizeLog2 - kSmiTagSize);
__ Addu(scratch, elements_reg, Operand(scratch4));
__ sw(mantissa_reg, FieldMemOperand(scratch, FixedDoubleArray::kHeaderSize));
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
__ sw(exponent_reg, FieldMemOperand(scratch, offset));
__ Ret();
__ bind(&maybe_nan);
// Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
// it's an Infinity, and the non-NaN code path applies.
__ li(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
__ Branch(&is_nan, gt, exponent_reg, Operand(scratch));
__ lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
__ Branch(&have_double_value, eq, mantissa_reg, Operand(zero_reg));
__ bind(&is_nan);
// Load canonical NaN for storing into the double array.
uint64_t nan_int64 = BitCast<uint64_t>(
FixedDoubleArray::canonical_not_the_hole_nan_as_double());
__ li(mantissa_reg, Operand(static_cast<uint32_t>(nan_int64)));
__ li(exponent_reg, Operand(static_cast<uint32_t>(nan_int64 >> 32)));
__ jmp(&have_double_value);
__ bind(&smi_value);
__ Addu(scratch, elements_reg,
Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
__ sll(scratch4, key_reg, kDoubleSizeLog2 - kSmiTagSize);
__ Addu(scratch, scratch, scratch4);
// scratch is now effective address of the double element
FloatingPointHelper::Destination destination;
if (CpuFeatures::IsSupported(FPU)) {
destination = FloatingPointHelper::kFPURegisters;
} else {
destination = FloatingPointHelper::kCoreRegisters;
}
__ SmiUntag(value_reg, value_reg);
FloatingPointHelper::ConvertIntToDouble(
masm, value_reg, destination,
f0, mantissa_reg, exponent_reg, // These are: double_dst, dst1, dst2.
scratch4, f2); // These are: scratch2, single_scratch.
if (destination == FloatingPointHelper::kFPURegisters) {
CpuFeatures::Scope scope(FPU);
__ sdc1(f0, MemOperand(scratch, 0));
} else {
__ sw(mantissa_reg, MemOperand(scratch, 0));
__ sw(exponent_reg, MemOperand(scratch, Register::kSizeInBytes));
}
__ Ret();
// Handle store cache miss, replacing the ic with the generic stub.
__ bind(&miss_force_generic);
Handle<Code> ic =
masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
__ Jump(ic, RelocInfo::CODE_TARGET);
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

41
deps/v8/src/mirror-debugger.js

@ -1250,9 +1250,9 @@ const kFrameDetailsNameIndex = 0;
const kFrameDetailsValueIndex = 1; const kFrameDetailsValueIndex = 1;
const kFrameDetailsNameValueSize = 2; const kFrameDetailsNameValueSize = 2;
const kFrameDetailsFlagDebuggerFrame = 1; const kFrameDetailsFlagDebuggerFrameMask = 1 << 0;
const kFrameDetailsFlagOptimizedFrame = 2; const kFrameDetailsFlagOptimizedFrameMask = 1 << 1;
const kFrameDetailsFlagInlinedFrame = 4; const kFrameDetailsFlagInlinedFrameIndexMask = 7 << 2;
/** /**
* Wrapper for the frame details information retreived from the VM. The frame * Wrapper for the frame details information retreived from the VM. The frame
@ -1266,7 +1266,7 @@ const kFrameDetailsFlagInlinedFrame = 4;
* 5: Source position * 5: Source position
* 6: Construct call * 6: Construct call
* 7: Is at return * 7: Is at return
* 8: Flags (debugger frame, optimized frame, inlined frame) * 8: Flags (debugger frame, optimized frame, inlined frame index)
* Arguments name, value * Arguments name, value
* Locals name, value * Locals name, value
* Return value if any * Return value if any
@ -1312,22 +1312,27 @@ FrameDetails.prototype.isAtReturn = function() {
FrameDetails.prototype.isDebuggerFrame = function() { FrameDetails.prototype.isDebuggerFrame = function() {
%CheckExecutionState(this.break_id_); %CheckExecutionState(this.break_id_);
var f = kFrameDetailsFlagDebuggerFrame; var f = kFrameDetailsFlagDebuggerFrameMask;
return (this.details_[kFrameDetailsFlagsIndex] & f) == f; return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
} }
FrameDetails.prototype.isOptimizedFrame = function() { FrameDetails.prototype.isOptimizedFrame = function() {
%CheckExecutionState(this.break_id_); %CheckExecutionState(this.break_id_);
var f = kFrameDetailsFlagOptimizedFrame; var f = kFrameDetailsFlagOptimizedFrameMask;
return (this.details_[kFrameDetailsFlagsIndex] & f) == f; return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
} }
FrameDetails.prototype.isInlinedFrame = function() { FrameDetails.prototype.isInlinedFrame = function() {
return this.inlinedFrameIndex() > 0;
}
FrameDetails.prototype.inlinedFrameIndex = function() {
%CheckExecutionState(this.break_id_); %CheckExecutionState(this.break_id_);
var f = kFrameDetailsFlagInlinedFrame; var f = kFrameDetailsFlagInlinedFrameIndexMask;
return (this.details_[kFrameDetailsFlagsIndex] & f) == f; return (this.details_[kFrameDetailsFlagsIndex] & f) >> 2
} }
@ -1476,6 +1481,11 @@ FrameMirror.prototype.isInlinedFrame = function() {
}; };
FrameMirror.prototype.inlinedFrameIndex = function() {
return this.details_.inlinedFrameIndex();
};
FrameMirror.prototype.argumentCount = function() { FrameMirror.prototype.argumentCount = function() {
return this.details_.argumentCount(); return this.details_.argumentCount();
}; };
@ -1565,8 +1575,12 @@ FrameMirror.prototype.scope = function(index) {
FrameMirror.prototype.evaluate = function(source, disable_break, opt_context_object) { FrameMirror.prototype.evaluate = function(source, disable_break, opt_context_object) {
var result = %DebugEvaluate(this.break_id_, this.details_.frameId(), var result = %DebugEvaluate(this.break_id_,
source, Boolean(disable_break), opt_context_object); this.details_.frameId(),
this.details_.inlinedFrameIndex(),
source,
Boolean(disable_break),
opt_context_object);
return MakeMirror(result); return MakeMirror(result);
}; };
@ -1591,8 +1605,10 @@ FrameMirror.prototype.invocationText = function() {
// Try to find the function as a property in the receiver. Include the // Try to find the function as a property in the receiver. Include the
// prototype chain in the lookup. // prototype chain in the lookup.
var property = GetUndefinedMirror(); var property = GetUndefinedMirror();
if (!receiver.isUndefined()) { if (receiver.isObject()) {
for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) { for (var r = receiver;
!r.isNull() && property.isUndefined();
r = r.protoObject()) {
property = r.lookupProperty(func); property = r.lookupProperty(func);
} }
} }
@ -1719,6 +1735,7 @@ function ScopeDetails(frame, index) {
this.break_id_ = frame.break_id_; this.break_id_ = frame.break_id_;
this.details_ = %GetScopeDetails(frame.break_id_, this.details_ = %GetScopeDetails(frame.break_id_,
frame.details_.frameId(), frame.details_.frameId(),
frame.details_.inlinedFrameIndex(),
index); index);
} }

2
deps/v8/src/natives.h

@ -36,7 +36,7 @@ typedef bool (*NativeSourceCallback)(Vector<const char> name,
int index); int index);
enum NativeType { enum NativeType {
CORE, EXPERIMENTAL, D8 CORE, EXPERIMENTAL, D8, TEST
}; };
template <NativeType type> template <NativeType type>

3
deps/v8/src/objects-debug.cc

@ -315,7 +315,8 @@ void FixedDoubleArray::FixedDoubleArrayVerify() {
if (!is_the_hole(i)) { if (!is_the_hole(i)) {
double value = get(i); double value = get(i);
ASSERT(!isnan(value) || ASSERT(!isnan(value) ||
BitCast<uint64_t>(value) == kCanonicalNonHoleNanInt64); (BitCast<uint64_t>(value) ==
BitCast<uint64_t>(canonical_not_the_hole_nan_as_double())));
} }
} }
} }

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

@ -1610,6 +1610,23 @@ void FixedArray::set(int index, Object* value) {
} }
inline bool FixedDoubleArray::is_the_hole_nan(double value) {
return BitCast<uint64_t, double>(value) == kHoleNanInt64;
}
inline double FixedDoubleArray::hole_nan_as_double() {
return BitCast<double, uint64_t>(kHoleNanInt64);
}
inline double FixedDoubleArray::canonical_not_the_hole_nan_as_double() {
ASSERT(BitCast<uint64_t>(OS::nan_value()) != kHoleNanInt64);
ASSERT((BitCast<uint64_t>(OS::nan_value()) >> 32) != kHoleNanUpper32);
return OS::nan_value();
}
double FixedDoubleArray::get(int index) { double FixedDoubleArray::get(int index) {
ASSERT(map() != HEAP->fixed_cow_array_map() && ASSERT(map() != HEAP->fixed_cow_array_map() &&
map() != HEAP->fixed_array_map()); map() != HEAP->fixed_array_map());
@ -3744,6 +3761,7 @@ void JSBuiltinsObject::set_javascript_builtin_code(Builtins::JavaScript id,
ACCESSORS(JSProxy, handler, Object, kHandlerOffset) ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
ACCESSORS(JSProxy, padding, Object, kPaddingOffset)
Address Foreign::address() { Address Foreign::address() {
@ -3989,7 +4007,8 @@ bool JSObject::HasIndexedInterceptor() {
bool JSObject::AllowsSetElementsLength() { bool JSObject::AllowsSetElementsLength() {
bool result = elements()->IsFixedArray(); bool result = elements()->IsFixedArray() ||
elements()->IsFixedDoubleArray();
ASSERT(result == !HasExternalArrayElements()); ASSERT(result == !HasExternalArrayElements());
return result; return result;
} }
@ -4139,6 +4158,22 @@ Object* JSReceiver::GetPrototype() {
} }
bool JSReceiver::HasProperty(String* name) {
if (IsJSProxy()) {
return JSProxy::cast(this)->HasPropertyWithHandler(name);
}
return GetPropertyAttribute(name) != ABSENT;
}
bool JSReceiver::HasLocalProperty(String* name) {
if (IsJSProxy()) {
return JSProxy::cast(this)->HasPropertyWithHandler(name);
}
return GetLocalPropertyAttribute(name) != ABSENT;
}
PropertyAttributes JSReceiver::GetPropertyAttribute(String* key) { PropertyAttributes JSReceiver::GetPropertyAttribute(String* key) {
return GetPropertyAttributeWithReceiver(this, key); return GetPropertyAttributeWithReceiver(this, key);
} }

255
deps/v8/src/objects.cc

@ -58,11 +58,6 @@ namespace internal {
const int kGetterIndex = 0; const int kGetterIndex = 0;
const int kSetterIndex = 1; const int kSetterIndex = 1;
uint64_t FixedDoubleArray::kHoleNanInt64 = -1;
uint64_t FixedDoubleArray::kCanonicalNonHoleNanLower32 = 0x7FF00000;
uint64_t FixedDoubleArray::kCanonicalNonHoleNanInt64 =
kCanonicalNonHoleNanLower32 << 32;
MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
Object* value) { Object* value) {
Object* result; Object* result;
@ -194,7 +189,7 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
AccessorInfo* data = AccessorInfo::cast(structure); AccessorInfo* data = AccessorInfo::cast(structure);
Object* fun_obj = data->getter(); Object* fun_obj = data->getter();
v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
HandleScope scope; HandleScope scope(isolate);
JSObject* self = JSObject::cast(receiver); JSObject* self = JSObject::cast(receiver);
JSObject* holder_handle = JSObject::cast(holder); JSObject* holder_handle = JSObject::cast(holder);
Handle<String> key(name); Handle<String> key(name);
@ -234,7 +229,7 @@ MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
String* name_raw, String* name_raw,
Object* handler_raw) { Object* handler_raw) {
Isolate* isolate = name_raw->GetIsolate(); Isolate* isolate = name_raw->GetIsolate();
HandleScope scope; HandleScope scope(isolate);
Handle<Object> receiver(receiver_raw); Handle<Object> receiver(receiver_raw);
Handle<Object> name(name_raw); Handle<Object> name(name_raw);
Handle<Object> handler(handler_raw); Handle<Object> handler(handler_raw);
@ -2178,9 +2173,9 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
} }
} }
HandleScope scope;
Handle<Object> value_handle(value);
Heap* heap = GetHeap(); Heap* heap = GetHeap();
HandleScope scope(heap->isolate());
Handle<Object> value_handle(value);
heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle; return *value_handle;
} }
@ -2201,13 +2196,38 @@ MaybeObject* JSReceiver::SetProperty(LookupResult* result,
} }
bool JSProxy::HasPropertyWithHandler(String* name_raw) {
Isolate* isolate = GetIsolate();
HandleScope scope(isolate);
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
Handle<Object> handler(this->handler());
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (trap->IsUndefined()) {
trap = isolate->derived_has_trap();
}
// Call trap function.
Object** args[] = { name.location() };
bool has_exception;
Handle<Object> result =
Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
if (has_exception) return Failure::Exception();
return result->ToBoolean()->IsTrue();
}
MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
String* name_raw, String* name_raw,
Object* value_raw, Object* value_raw,
PropertyAttributes attributes, PropertyAttributes attributes,
StrictModeFlag strict_mode) { StrictModeFlag strict_mode) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
HandleScope scope; HandleScope scope(isolate);
Handle<Object> receiver(this); Handle<Object> receiver(this);
Handle<Object> name(name_raw); Handle<Object> name(name_raw);
Handle<Object> value(value_raw); Handle<Object> value(value_raw);
@ -2225,11 +2245,48 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
receiver.location(), name.location(), value.location() receiver.location(), name.location(), value.location()
}; };
bool has_exception; bool has_exception;
Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
if (has_exception) return Failure::Exception();
return *value;
}
MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
String* name_raw, DeleteMode mode) {
Isolate* isolate = GetIsolate();
HandleScope scope(isolate);
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
Handle<Object> handler(this->handler());
// Extract trap function.
Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (trap->IsUndefined()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
"handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
isolate->Throw(*error);
return Failure::Exception();
}
// Call trap function.
Object** args[] = { name.location() };
bool has_exception;
Handle<Object> result = Handle<Object> result =
Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
if (has_exception) return Failure::Exception(); if (has_exception) return Failure::Exception();
return *value; Object* bool_result = result->ToBoolean();
if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
"handler_failed", HandleVector(args, ARRAY_SIZE(args)));
isolate->Throw(*error);
return Failure::Exception();
}
return bool_result;
} }
@ -2238,7 +2295,7 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
String* name_raw, String* name_raw,
bool* has_exception) { bool* has_exception) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
HandleScope scope; HandleScope scope(isolate);
Handle<JSReceiver> receiver(receiver_raw); Handle<JSReceiver> receiver(receiver_raw);
Handle<Object> name(name_raw); Handle<Object> name(name_raw);
Handle<Object> handler(this->handler()); Handle<Object> handler(this->handler());
@ -2268,6 +2325,18 @@ MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
} }
void JSProxy::Fix() {
Isolate* isolate = GetIsolate();
HandleScope scope(isolate);
Handle<JSProxy> self(this);
isolate->factory()->BecomeJSObject(self);
ASSERT(IsJSObject());
// TODO(rossberg): recognize function proxies.
}
MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
String* name, String* name,
Object* value, Object* value,
@ -2327,7 +2396,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
} }
if (result->IsReadOnly() && result->IsProperty()) { if (result->IsReadOnly() && result->IsProperty()) {
if (strict_mode == kStrictMode) { if (strict_mode == kStrictMode) {
HandleScope scope; HandleScope scope(heap->isolate());
Handle<String> key(name); Handle<String> key(name);
Handle<Object> holder(this); Handle<Object> holder(this);
Handle<Object> args[2] = { key, holder }; Handle<Object> args[2] = { key, holder };
@ -2811,16 +2880,18 @@ MaybeObject* JSObject::NormalizeElements() {
ASSERT(!HasExternalArrayElements()); ASSERT(!HasExternalArrayElements());
// Find the backing store. // Find the backing store.
FixedArray* array = FixedArray::cast(elements()); FixedArrayBase* array = FixedArrayBase::cast(elements());
Map* old_map = array->map(); Map* old_map = array->map();
bool is_arguments = bool is_arguments =
(old_map == old_map->heap()->non_strict_arguments_elements_map()); (old_map == old_map->heap()->non_strict_arguments_elements_map());
if (is_arguments) { if (is_arguments) {
array = FixedArray::cast(array->get(1)); array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
} }
if (array->IsDictionary()) return array; if (array->IsDictionary()) return array;
ASSERT(HasFastElements() || HasFastArgumentsElements()); ASSERT(HasFastElements() ||
HasFastDoubleElements() ||
HasFastArgumentsElements());
// Compute the effective length and allocate a new backing store. // Compute the effective length and allocate a new backing store.
int length = IsJSArray() int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value() ? Smi::cast(JSArray::cast(this)->length())->value()
@ -2833,7 +2904,7 @@ MaybeObject* JSObject::NormalizeElements() {
} }
// Copy the elements to the new backing store. // Copy the elements to the new backing store.
bool has_double_elements = old_map->has_fast_double_elements(); bool has_double_elements = array->IsFixedDoubleArray();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Object* value = NULL; Object* value = NULL;
if (has_double_elements) { if (has_double_elements) {
@ -2851,7 +2922,7 @@ MaybeObject* JSObject::NormalizeElements() {
} }
} else { } else {
ASSERT(old_map->has_fast_elements()); ASSERT(old_map->has_fast_elements());
value = array->get(i); value = FixedArray::cast(array)->get(i);
} }
PropertyDetails details = PropertyDetails(NONE, NORMAL); PropertyDetails details = PropertyDetails(NONE, NORMAL);
if (!value->IsTheHole()) { if (!value->IsTheHole()) {
@ -3135,7 +3206,7 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
case FAST_DOUBLE_ELEMENTS: { case FAST_DOUBLE_ELEMENTS: {
int length = IsJSArray() int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value() ? Smi::cast(JSArray::cast(this)->length())->value()
: FixedArray::cast(elements())->length(); : FixedDoubleArray::cast(elements())->length();
if (index < static_cast<uint32_t>(length)) { if (index < static_cast<uint32_t>(length)) {
FixedDoubleArray::cast(elements())->set_the_hole(index); FixedDoubleArray::cast(elements())->set_the_hole(index);
} }
@ -3179,6 +3250,15 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
} }
MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
if (IsJSProxy()) {
return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
} else {
return JSObject::cast(this)->DeleteProperty(name, mode);
}
}
MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
// ECMA-262, 3rd, 8.6.2.5 // ECMA-262, 3rd, 8.6.2.5
@ -7317,22 +7397,28 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
new_map = Map::cast(object); new_map = Map::cast(object);
} }
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
switch (GetElementsKind()) { switch (GetElementsKind()) {
case FAST_ELEMENTS: case FAST_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode); CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
set_map(new_map); set_map(new_map);
set_elements(new_elements); set_elements(new_elements);
break; break;
case DICTIONARY_ELEMENTS: }
case DICTIONARY_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
CopySlowElementsToFast(NumberDictionary::cast(elements()), CopySlowElementsToFast(NumberDictionary::cast(elements()),
new_elements, new_elements,
mode); mode);
set_map(new_map); set_map(new_map);
set_elements(new_elements); set_elements(new_elements);
break; break;
}
case NON_STRICT_ARGUMENTS_ELEMENTS: { case NON_STRICT_ARGUMENTS_ELEMENTS: {
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
// The object's map and the parameter map are unchanged, the unaliased // The object's map and the parameter map are unchanged, the unaliased
// arguments are copied to the new backing store. // arguments are copied to the new backing store.
FixedArray* parameter_map = FixedArray::cast(elements()); FixedArray* parameter_map = FixedArray::cast(elements());
@ -7368,6 +7454,8 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
new_elements->set(i, obj, UPDATE_WRITE_BARRIER); new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
} }
} }
set_map(new_map);
set_elements(new_elements);
break; break;
} }
case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS:
@ -7430,7 +7518,9 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
break; break;
} }
ASSERT(new_map->has_fast_double_elements());
set_map(new_map); set_map(new_map);
ASSERT(elems->IsFixedDoubleArray());
set_elements(elems); set_elements(elems);
if (IsJSArray()) { if (IsJSArray()) {
@ -7520,7 +7610,7 @@ void JSArray::Expand(int required_size) {
static Failure* ArrayLengthRangeError(Heap* heap) { static Failure* ArrayLengthRangeError(Heap* heap) {
HandleScope scope; HandleScope scope(heap->isolate());
return heap->isolate()->Throw( return heap->isolate()->Throw(
*FACTORY->NewRangeError("invalid_array_length", *FACTORY->NewRangeError("invalid_array_length",
HandleVector<Object>(NULL, 0))); HandleVector<Object>(NULL, 0)));
@ -7536,32 +7626,57 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value(); const int value = Smi::cast(smi_length)->value();
if (value < 0) return ArrayLengthRangeError(GetHeap()); if (value < 0) return ArrayLengthRangeError(GetHeap());
switch (GetElementsKind()) { JSObject::ElementsKind elements_kind = GetElementsKind();
case FAST_ELEMENTS: { switch (elements_kind) {
int old_capacity = FixedArray::cast(elements())->length(); case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS: {
int old_capacity = FixedArrayBase::cast(elements())->length();
if (value <= old_capacity) { if (value <= old_capacity) {
if (IsJSArray()) { if (IsJSArray()) {
Object* obj; Object* obj;
{ MaybeObject* maybe_obj = EnsureWritableFastElements(); if (elements_kind == FAST_ELEMENTS) {
MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj;
} }
FixedArray* fast_elements = FixedArray::cast(elements());
if (2 * value <= old_capacity) { if (2 * value <= old_capacity) {
// If more than half the elements won't be used, trim the array. // If more than half the elements won't be used, trim the array.
if (value == 0) { if (value == 0) {
initialize_elements(); initialize_elements();
} else { } else {
fast_elements->set_length(value); Address filler_start;
Address filler_start = fast_elements->address() + int filler_size;
FixedArray::OffsetOfElementAt(value); if (GetElementsKind() == FAST_ELEMENTS) {
int filler_size = (old_capacity - value) * kPointerSize; FixedArray* fast_elements = FixedArray::cast(elements());
fast_elements->set_length(value);
filler_start = fast_elements->address() +
FixedArray::OffsetOfElementAt(value);
filler_size = (old_capacity - value) * kPointerSize;
} else {
ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
FixedDoubleArray* fast_double_elements =
FixedDoubleArray::cast(elements());
fast_double_elements->set_length(value);
filler_start = fast_double_elements->address() +
FixedDoubleArray::OffsetOfElementAt(value);
filler_size = (old_capacity - value) * kDoubleSize;
}
GetHeap()->CreateFillerObjectAt(filler_start, filler_size); GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
} }
} else { } else {
// Otherwise, fill the unused tail with holes. // Otherwise, fill the unused tail with holes.
int old_length = FastD2I(JSArray::cast(this)->length()->Number()); int old_length = FastD2I(JSArray::cast(this)->length()->Number());
for (int i = value; i < old_length; i++) { if (GetElementsKind() == FAST_ELEMENTS) {
fast_elements->set_the_hole(i); FixedArray* fast_elements = FixedArray::cast(elements());
for (int i = value; i < old_length; i++) {
fast_elements->set_the_hole(i);
}
} else {
ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
FixedDoubleArray* fast_double_elements =
FixedDoubleArray::cast(elements());
for (int i = value; i < old_length; i++) {
fast_double_elements->set_the_hole(i);
}
} }
} }
JSArray::cast(this)->set_length(Smi::cast(smi_length)); JSArray::cast(this)->set_length(Smi::cast(smi_length));
@ -7572,8 +7687,14 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
int new_capacity = value > min ? value : min; int new_capacity = value > min ? value : min;
if (new_capacity <= kMaxFastElementsLength || if (new_capacity <= kMaxFastElementsLength ||
!ShouldConvertToSlowElements(new_capacity)) { !ShouldConvertToSlowElements(new_capacity)) {
MaybeObject* result = MaybeObject* result;
SetFastElementsCapacityAndLength(new_capacity, value); if (GetElementsKind() == FAST_ELEMENTS) {
result = SetFastElementsCapacityAndLength(new_capacity, value);
} else {
ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
result = SetFastDoubleElementsCapacityAndLength(new_capacity,
value);
}
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
return this; return this;
} }
@ -7609,7 +7730,6 @@ MaybeObject* JSObject::SetElementsLength(Object* len) {
case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_PIXEL_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
UNREACHABLE(); UNREACHABLE();
break; break;
} }
@ -7718,7 +7838,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
// or [[Extensible]] must not violate the invariants defined in the preceding // or [[Extensible]] must not violate the invariants defined in the preceding
// paragraph. // paragraph.
if (!this->map()->is_extensible()) { if (!this->map()->is_extensible()) {
HandleScope scope; HandleScope scope(heap->isolate());
Handle<Object> handle(this, heap->isolate()); Handle<Object> handle(this, heap->isolate());
return heap->isolate()->Throw( return heap->isolate()->Throw(
*FACTORY->NewTypeError("non_extensible_proto", *FACTORY->NewTypeError("non_extensible_proto",
@ -7732,7 +7852,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value,
for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
if (JSObject::cast(pt) == this) { if (JSObject::cast(pt) == this) {
// Cycle detected. // Cycle detected.
HandleScope scope; HandleScope scope(heap->isolate());
return heap->isolate()->Throw( return heap->isolate()->Throw(
*FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
} }
@ -8022,6 +8142,15 @@ bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
!FixedArray::cast(elements())->get(index)->IsTheHole()) return true; !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
break; break;
} }
case FAST_DOUBLE_ELEMENTS: {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>
(Smi::cast(JSArray::cast(this)->length())->value()) :
static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
if ((index < length) &&
!FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
break;
}
case EXTERNAL_PIXEL_ELEMENTS: { case EXTERNAL_PIXEL_ELEMENTS: {
ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) { if (index < static_cast<uint32_t>(pixels->length())) {
@ -8043,9 +8172,6 @@ bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
} }
break; break;
} }
case FAST_DOUBLE_ELEMENTS:
UNREACHABLE();
break;
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index) if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) { != NumberDictionary::kNotFound) {
@ -8407,8 +8533,9 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
} else { } else {
new_length = dictionary->max_number_key() + 1; new_length = dictionary->max_number_key() + 1;
} }
MaybeObject* result = MaybeObject* result = ShouldConvertToFastDoubleElements()
SetFastElementsCapacityAndLength(new_length, new_length); ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
: SetFastElementsCapacityAndLength(new_length, new_length);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
#ifdef DEBUG #ifdef DEBUG
if (FLAG_trace_normalization) { if (FLAG_trace_normalization) {
@ -8495,6 +8622,9 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
} }
// Otherwise default to slow case. // Otherwise default to slow case.
ASSERT(HasFastDoubleElements());
ASSERT(map()->has_fast_double_elements());
ASSERT(elements()->IsFixedDoubleArray());
Object* obj; Object* obj;
{ MaybeObject* maybe_obj = NormalizeElements(); { MaybeObject* maybe_obj = NormalizeElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@ -8512,7 +8642,7 @@ MaybeObject* JSObject::SetElement(uint32_t index,
if (IsAccessCheckNeeded()) { if (IsAccessCheckNeeded()) {
Heap* heap = GetHeap(); Heap* heap = GetHeap();
if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
HandleScope scope; HandleScope scope(heap->isolate());
Handle<Object> value_handle(value); Handle<Object> value_handle(value);
heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle; return *value_handle;
@ -8948,10 +9078,13 @@ bool JSObject::HasDenseElements() {
int capacity = 0; int capacity = 0;
int number_of_elements = 0; int number_of_elements = 0;
FixedArray* backing_store = FixedArray::cast(elements()); FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
FixedArray* backing_store = NULL;
switch (GetElementsKind()) { switch (GetElementsKind()) {
case NON_STRICT_ARGUMENTS_ELEMENTS: case NON_STRICT_ARGUMENTS_ELEMENTS:
backing_store = FixedArray::cast(backing_store->get(1)); backing_store_base =
FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
backing_store = FixedArray::cast(backing_store_base);
if (backing_store->IsDictionary()) { if (backing_store->IsDictionary()) {
NumberDictionary* dictionary = NumberDictionary::cast(backing_store); NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
capacity = dictionary->Capacity(); capacity = dictionary->Capacity();
@ -8960,13 +9093,15 @@ bool JSObject::HasDenseElements() {
} }
// Fall through. // Fall through.
case FAST_ELEMENTS: case FAST_ELEMENTS:
backing_store = FixedArray::cast(backing_store_base);
capacity = backing_store->length(); capacity = backing_store->length();
for (int i = 0; i < capacity; ++i) { for (int i = 0; i < capacity; ++i) {
if (!backing_store->get(i)->IsTheHole()) ++number_of_elements; if (!backing_store->get(i)->IsTheHole()) ++number_of_elements;
} }
break; break;
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
NumberDictionary* dictionary = NumberDictionary::cast(backing_store); NumberDictionary* dictionary =
NumberDictionary::cast(FixedArray::cast(elements()));
capacity = dictionary->Capacity(); capacity = dictionary->Capacity();
number_of_elements = dictionary->NumberOfElements(); number_of_elements = dictionary->NumberOfElements();
break; break;
@ -9474,6 +9609,21 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
ASSERT(!storage || storage->length() >= counter); ASSERT(!storage || storage->length() >= counter);
break; break;
} }
case FAST_DOUBLE_ELEMENTS: {
int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() :
FixedDoubleArray::cast(elements())->length();
for (int i = 0; i < length; i++) {
if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
if (storage != NULL) {
storage->set(counter, Smi::FromInt(i));
}
counter++;
}
}
ASSERT(!storage || storage->length() >= counter);
break;
}
case EXTERNAL_PIXEL_ELEMENTS: { case EXTERNAL_PIXEL_ELEMENTS: {
int length = ExternalPixelArray::cast(elements())->length(); int length = ExternalPixelArray::cast(elements())->length();
while (counter < length) { while (counter < length) {
@ -9503,9 +9653,6 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
ASSERT(!storage || storage->length() >= counter); ASSERT(!storage || storage->length() >= counter);
break; break;
} }
case FAST_DOUBLE_ELEMENTS:
UNREACHABLE();
break;
case DICTIONARY_ELEMENTS: { case DICTIONARY_ELEMENTS: {
if (storage != NULL) { if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage, element_dictionary()->CopyKeysTo(storage,
@ -11053,11 +11200,11 @@ void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
template<typename Shape, typename Key> template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::DeleteProperty(int entry, Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
JSObject::DeleteMode mode) { JSReceiver::DeleteMode mode) {
Heap* heap = Dictionary<Shape, Key>::GetHeap(); Heap* heap = Dictionary<Shape, Key>::GetHeap();
PropertyDetails details = DetailsAt(entry); PropertyDetails details = DetailsAt(entry);
// Ignore attributes if forcing a deletion. // Ignore attributes if forcing a deletion.
if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
return heap->false_value(); return heap->false_value();
} }
SetEntry(entry, heap->null_value(), heap->null_value()); SetEntry(entry, heap->null_value(), heap->null_value());

72
deps/v8/src/objects.h

@ -1359,6 +1359,12 @@ class HeapNumber: public HeapObject {
// JSObject and JSProxy. // JSObject and JSProxy.
class JSReceiver: public HeapObject { class JSReceiver: public HeapObject {
public: public:
enum DeleteMode {
NORMAL_DELETION,
STRICT_DELETION,
FORCE_DELETION
};
// Casting. // Casting.
static inline JSReceiver* cast(Object* obj); static inline JSReceiver* cast(Object* obj);
@ -1373,6 +1379,8 @@ class JSReceiver: public HeapObject {
PropertyAttributes attributes, PropertyAttributes attributes,
StrictModeFlag strict_mode); StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode);
// Returns the class name ([[Class]] property in the specification). // Returns the class name ([[Class]] property in the specification).
String* class_name(); String* class_name();
@ -1386,14 +1394,8 @@ class JSReceiver: public HeapObject {
PropertyAttributes GetLocalPropertyAttribute(String* name); PropertyAttributes GetLocalPropertyAttribute(String* name);
// Can cause a GC. // Can cause a GC.
bool HasProperty(String* name) { inline bool HasProperty(String* name);
return GetPropertyAttribute(name) != ABSENT; inline bool HasLocalProperty(String* name);
}
// Can cause a GC.
bool HasLocalProperty(String* name) {
return GetLocalPropertyAttribute(name) != ABSENT;
}
// Return the object's prototype (might be Heap::null_value()). // Return the object's prototype (might be Heap::null_value()).
inline Object* GetPrototype(); inline Object* GetPrototype();
@ -1422,12 +1424,6 @@ class JSReceiver: public HeapObject {
// caching. // caching.
class JSObject: public JSReceiver { class JSObject: public JSReceiver {
public: public:
enum DeleteMode {
NORMAL_DELETION,
STRICT_DELETION,
FORCE_DELETION
};
enum ElementsKind { enum ElementsKind {
// The "fast" kind for tagged values. Must be first to make it possible // The "fast" kind for tagged values. Must be first to make it possible
// to efficiently check maps if they have fast elements. // to efficiently check maps if they have fast elements.
@ -2173,23 +2169,12 @@ class FixedDoubleArray: public FixedArrayBase {
return kHeaderSize + length * kDoubleSize; return kHeaderSize + length * kDoubleSize;
} }
// The following can't be declared inline as const static // Code Generation support.
// because they're 64-bit. static int OffsetOfElementAt(int index) { return SizeFor(index); }
static uint64_t kCanonicalNonHoleNanLower32;
static uint64_t kCanonicalNonHoleNanInt64;
static uint64_t kHoleNanInt64;
inline static bool is_the_hole_nan(double value) {
return BitCast<uint64_t, double>(value) == kHoleNanInt64;
}
inline static double hole_nan_as_double() {
return BitCast<double, uint64_t>(kHoleNanInt64);
}
inline static double canonical_not_the_hole_nan_as_double() { inline static bool is_the_hole_nan(double value);
return BitCast<double, uint64_t>(kCanonicalNonHoleNanInt64); inline static double hole_nan_as_double();
} inline static double canonical_not_the_hole_nan_as_double();
// Casting. // Casting.
static inline FixedDoubleArray* cast(Object* obj); static inline FixedDoubleArray* cast(Object* obj);
@ -6487,20 +6472,32 @@ class JSProxy: public JSReceiver {
// [handler]: The handler property. // [handler]: The handler property.
DECL_ACCESSORS(handler, Object) DECL_ACCESSORS(handler, Object)
// [padding]: The padding slot (unused, see below).
DECL_ACCESSORS(padding, Object)
// Casting. // Casting.
static inline JSProxy* cast(Object* obj); static inline JSProxy* cast(Object* obj);
bool HasPropertyWithHandler(String* name);
MUST_USE_RESULT MaybeObject* SetPropertyWithHandler( MUST_USE_RESULT MaybeObject* SetPropertyWithHandler(
String* name_raw, String* name,
Object* value_raw, Object* value,
PropertyAttributes attributes, PropertyAttributes attributes,
StrictModeFlag strict_mode); StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* DeletePropertyWithHandler(
String* name,
DeleteMode mode);
MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler( MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler(
JSReceiver* receiver, JSReceiver* receiver,
String* name_raw, String* name,
bool* has_exception); bool* has_exception);
// Turn this into an (empty) JSObject.
void Fix();
// Dispatched behavior. // Dispatched behavior.
#ifdef OBJECT_PRINT #ifdef OBJECT_PRINT
inline void JSProxyPrint() { inline void JSProxyPrint() {
@ -6512,9 +6509,14 @@ class JSProxy: public JSReceiver {
void JSProxyVerify(); void JSProxyVerify();
#endif #endif
// Layout description. // Layout description. We add padding so that a proxy has the same
// size as a virgin JSObject. This is essential for becoming a JSObject
// upon freeze.
static const int kHandlerOffset = HeapObject::kHeaderSize; static const int kHandlerOffset = HeapObject::kHeaderSize;
static const int kSize = kHandlerOffset + kPointerSize; static const int kPaddingOffset = kHandlerOffset + kPointerSize;
static const int kSize = kPaddingOffset + kPointerSize;
STATIC_CHECK(kSize == JSObject::kHeaderSize);
typedef FixedBodyDescriptor<kHandlerOffset, typedef FixedBodyDescriptor<kHandlerOffset,
kHandlerOffset + kPointerSize, kHandlerOffset + kPointerSize,

186
deps/v8/src/parser.cc

@ -648,6 +648,7 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
} }
if (ok) { if (ok) {
result = new(zone()) FunctionLiteral( result = new(zone()) FunctionLiteral(
isolate(),
no_name, no_name,
top_scope_, top_scope_,
body, body,
@ -718,7 +719,6 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
{ {
// Parse the function literal. // Parse the function literal.
Handle<String> no_name = isolate()->factory()->empty_symbol();
Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with()); Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
if (!info->closure().is_null()) { if (!info->closure().is_null()) {
scope = Scope::DeserializeScopeChain(info, scope); scope = Scope::DeserializeScopeChain(info, scope);
@ -1262,7 +1262,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
// one must take great care not to treat it as a // one must take great care not to treat it as a
// fall-through. It is much easier just to wrap the entire // fall-through. It is much easier just to wrap the entire
// try-statement in a statement block and put the labels there // try-statement in a statement block and put the labels there
Block* result = new(zone()) Block(labels, 1, false); Block* result = new(zone()) Block(isolate(), labels, 1, false);
Target target(&this->target_stack_, result); Target target(&this->target_stack_, result);
TryStatement* statement = ParseTryStatement(CHECK_OK); TryStatement* statement = ParseTryStatement(CHECK_OK);
if (statement) { if (statement) {
@ -1453,10 +1453,10 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
// introduced dynamically when we meet their declarations, whereas // introduced dynamically when we meet their declarations, whereas
// other functions are setup when entering the surrounding scope. // other functions are setup when entering the surrounding scope.
SharedFunctionInfoLiteral* lit = SharedFunctionInfoLiteral* lit =
new(zone()) SharedFunctionInfoLiteral(shared); new(zone()) SharedFunctionInfoLiteral(isolate(), shared);
VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK); VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK);
return new(zone()) ExpressionStatement(new(zone()) Assignment( return new(zone()) ExpressionStatement(new(zone()) Assignment(
Token::INIT_VAR, var, lit, RelocInfo::kNoPosition)); isolate(), Token::INIT_VAR, var, lit, RelocInfo::kNoPosition));
} }
@ -1489,7 +1489,7 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
// (ECMA-262, 3rd, 12.2) // (ECMA-262, 3rd, 12.2)
// //
// Construct block expecting 16 statements. // Construct block expecting 16 statements.
Block* result = new(zone()) Block(labels, 16, false); Block* result = new(zone()) Block(isolate(), labels, 16, false);
Target target(&this->target_stack_, result); Target target(&this->target_stack_, result);
Expect(Token::LBRACE, CHECK_OK); Expect(Token::LBRACE, CHECK_OK);
InitializationBlockFinder block_finder(top_scope_, target_stack_); InitializationBlockFinder block_finder(top_scope_, target_stack_);
@ -1564,7 +1564,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// is inside an initializer block, it is ignored. // is inside an initializer block, it is ignored.
// //
// Create new block with one expected declaration. // Create new block with one expected declaration.
Block* block = new(zone()) Block(NULL, 1, true); Block* block = new(zone()) Block(isolate(), NULL, 1, true);
int nvars = 0; // the number of variables declared int nvars = 0; // the number of variables declared
Handle<String> name; Handle<String> name;
do { do {
@ -1676,7 +1676,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// Compute the arguments for the runtime call. // Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3); ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
// We have at least 1 parameter. // We have at least 1 parameter.
arguments->Add(new(zone()) Literal(name)); arguments->Add(NewLiteral(name));
CallRuntime* initialize; CallRuntime* initialize;
if (is_const) { if (is_const) {
@ -1689,9 +1689,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// the number of arguments (1 or 2). // the number of arguments (1 or 2).
initialize = initialize =
new(zone()) CallRuntime( new(zone()) CallRuntime(
isolate()->factory()->InitializeConstGlobal_symbol(), isolate(),
Runtime::FunctionForId(Runtime::kInitializeConstGlobal), isolate()->factory()->InitializeConstGlobal_symbol(),
arguments); Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
arguments);
} else { } else {
// Add strict mode. // Add strict mode.
// We may want to pass singleton to avoid Literal allocations. // We may want to pass singleton to avoid Literal allocations.
@ -1715,9 +1716,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
// the number of arguments (2 or 3). // the number of arguments (2 or 3).
initialize = initialize =
new(zone()) CallRuntime( new(zone()) CallRuntime(
isolate()->factory()->InitializeVarGlobal_symbol(), isolate(),
Runtime::FunctionForId(Runtime::kInitializeVarGlobal), isolate()->factory()->InitializeVarGlobal_symbol(),
arguments); Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
arguments);
} }
block->AddStatement(new(zone()) ExpressionStatement(initialize)); block->AddStatement(new(zone()) ExpressionStatement(initialize));
@ -1739,7 +1741,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
VariableProxy* proxy = VariableProxy* proxy =
initialization_scope->NewUnresolved(name, in_with); initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment = Assignment* assignment =
new(zone()) Assignment(op, proxy, value, position); new(zone()) Assignment(isolate(), op, proxy, value, position);
if (block) { if (block) {
block->AddStatement(new(zone()) ExpressionStatement(assignment)); block->AddStatement(new(zone()) ExpressionStatement(assignment));
} }
@ -1842,7 +1844,8 @@ IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) {
} else { } else {
else_statement = EmptyStatement(); else_statement = EmptyStatement();
} }
return new(zone()) IfStatement(condition, then_statement, else_statement); return new(zone()) IfStatement(
isolate(), condition, then_statement, else_statement);
} }
@ -1961,17 +1964,17 @@ Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) {
// Create resulting block with two statements. // Create resulting block with two statements.
// 1: Evaluate the with expression. // 1: Evaluate the with expression.
// 2: The try-finally block evaluating the body. // 2: The try-finally block evaluating the body.
Block* result = new(zone()) Block(NULL, 2, false); Block* result = new(zone()) Block(isolate(), NULL, 2, false);
if (result != NULL) { if (result != NULL) {
result->AddStatement(new(zone()) EnterWithContextStatement(obj)); result->AddStatement(new(zone()) EnterWithContextStatement(obj));
// Create body block. // Create body block.
Block* body = new(zone()) Block(NULL, 1, false); Block* body = new(zone()) Block(isolate(), NULL, 1, false);
body->AddStatement(stat); body->AddStatement(stat);
// Create exit block. // Create exit block.
Block* exit = new(zone()) Block(NULL, 1, false); Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
exit->AddStatement(new(zone()) ExitContextStatement()); exit->AddStatement(new(zone()) ExitContextStatement());
// Return a try-finally statement. // Return a try-finally statement.
@ -2032,7 +2035,7 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
statements->Add(stat); statements->Add(stat);
} }
return new(zone()) CaseClause(label, statements, pos); return new(zone()) CaseClause(isolate(), label, statements, pos);
} }
@ -2041,7 +2044,7 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
// SwitchStatement :: // SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}' // 'switch' '(' Expression ')' '{' CaseClause* '}'
SwitchStatement* statement = new(zone()) SwitchStatement(labels); SwitchStatement* statement = new(zone()) SwitchStatement(isolate(), labels);
Target target(&this->target_stack_, statement); Target target(&this->target_stack_, statement);
Expect(Token::SWITCH, CHECK_OK); Expect(Token::SWITCH, CHECK_OK);
@ -2077,7 +2080,8 @@ Statement* Parser::ParseThrowStatement(bool* ok) {
Expression* exception = ParseExpression(true, CHECK_OK); Expression* exception = ParseExpression(true, CHECK_OK);
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return new(zone()) ExpressionStatement(new(zone()) Throw(exception, pos)); return new(zone()) ExpressionStatement(
new(zone()) Throw(isolate(), exception, pos));
} }
@ -2156,7 +2160,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
} }
// Create exit block. // Create exit block.
Block* inner_finally = new(zone()) Block(NULL, 1, false); Block* inner_finally = new(zone()) Block(isolate(), NULL, 1, false);
inner_finally->AddStatement(new(zone()) ExitContextStatement()); inner_finally->AddStatement(new(zone()) ExitContextStatement());
// Create a try/finally statement. // Create a try/finally statement.
@ -2164,7 +2168,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
new(zone()) TryFinallyStatement(inner_body, inner_finally); new(zone()) TryFinallyStatement(inner_body, inner_finally);
inner_try_finally->set_escaping_targets(inner_collector.targets()); inner_try_finally->set_escaping_targets(inner_collector.targets());
catch_block = new(zone()) Block(NULL, 1, false); catch_block = new(zone()) Block(isolate(), NULL, 1, false);
catch_block->AddStatement(inner_try_finally); catch_block->AddStatement(inner_try_finally);
} else { } else {
Expect(Token::LBRACE, CHECK_OK); Expect(Token::LBRACE, CHECK_OK);
@ -2193,7 +2197,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
catch_variable, catch_variable,
catch_block); catch_block);
statement->set_escaping_targets(try_collector.targets()); statement->set_escaping_targets(try_collector.targets());
try_block = new(zone()) Block(NULL, 1, false); try_block = new(zone()) Block(isolate(), NULL, 1, false);
try_block->AddStatement(statement); try_block->AddStatement(statement);
catch_block = NULL; // Clear to indicate it's been handled. catch_block = NULL; // Clear to indicate it's been handled.
} }
@ -2224,7 +2228,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
// DoStatement :: // DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';' // 'do' Statement 'while' '(' Expression ')' ';'
DoWhileStatement* loop = new(zone()) DoWhileStatement(labels); DoWhileStatement* loop = new(zone()) DoWhileStatement(isolate(), labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
Expect(Token::DO, CHECK_OK); Expect(Token::DO, CHECK_OK);
@ -2255,7 +2259,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
// WhileStatement :: // WhileStatement ::
// 'while' '(' Expression ')' Statement // 'while' '(' Expression ')' Statement
WhileStatement* loop = new(zone()) WhileStatement(labels); WhileStatement* loop = new(zone()) WhileStatement(isolate(), labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
Expect(Token::WHILE, CHECK_OK); Expect(Token::WHILE, CHECK_OK);
@ -2285,7 +2289,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
if (peek() == Token::IN && !name.is_null()) { if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with()); VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
ForInStatement* loop = new(zone()) ForInStatement(labels); ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
Expect(Token::IN, CHECK_OK); Expect(Token::IN, CHECK_OK);
@ -2294,7 +2298,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
Statement* body = ParseStatement(NULL, CHECK_OK); Statement* body = ParseStatement(NULL, CHECK_OK);
loop->Initialize(each, enumerable, body); loop->Initialize(each, enumerable, body);
Block* result = new(zone()) Block(NULL, 2, false); Block* result = new(zone()) Block(isolate(), NULL, 2, false);
result->AddStatement(variable_statement); result->AddStatement(variable_statement);
result->AddStatement(loop); result->AddStatement(loop);
// Parsed for-in loop w/ variable/const declaration. // Parsed for-in loop w/ variable/const declaration.
@ -2315,7 +2319,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
isolate()->factory()->invalid_lhs_in_for_in_symbol(); isolate()->factory()->invalid_lhs_in_for_in_symbol();
expression = NewThrowReferenceError(type); expression = NewThrowReferenceError(type);
} }
ForInStatement* loop = new(zone()) ForInStatement(labels); ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
Expect(Token::IN, CHECK_OK); Expect(Token::IN, CHECK_OK);
@ -2334,7 +2338,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
} }
// Standard 'for' loop // Standard 'for' loop
ForStatement* loop = new(zone()) ForStatement(labels); ForStatement* loop = new(zone()) ForStatement(isolate(), labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
// Parsed initializer at this point. // Parsed initializer at this point.
@ -2370,7 +2374,8 @@ Expression* Parser::ParseExpression(bool accept_IN, bool* ok) {
Expect(Token::COMMA, CHECK_OK); Expect(Token::COMMA, CHECK_OK);
int position = scanner().location().beg_pos; int position = scanner().location().beg_pos;
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
result = new(zone()) BinaryOperation(Token::COMMA, result, right, position); result = new(zone()) BinaryOperation(
isolate(), Token::COMMA, result, right, position);
} }
return result; return result;
} }
@ -2442,7 +2447,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
fni_->Leave(); fni_->Leave();
} }
return new(zone()) Assignment(op, expression, right, pos); return new(zone()) Assignment(isolate(), op, expression, right, pos);
} }
@ -2464,8 +2469,8 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
Expect(Token::COLON, CHECK_OK); Expect(Token::COLON, CHECK_OK);
int right_position = scanner().peek_location().beg_pos; int right_position = scanner().peek_location().beg_pos;
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
return new(zone()) Conditional(expression, left, right, return new(zone()) Conditional(
left_position, right_position); isolate(), expression, left, right, left_position, right_position);
} }
@ -2552,12 +2557,12 @@ Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
x = NewCompareNode(cmp, x, y, position); x = NewCompareNode(cmp, x, y, position);
if (cmp != op) { if (cmp != op) {
// The comparison was negated - add a NOT. // The comparison was negated - add a NOT.
x = new(zone()) UnaryOperation(Token::NOT, x, position); x = new(zone()) UnaryOperation(isolate(), Token::NOT, x, position);
} }
} else { } else {
// We have a "normal" binary operation. // We have a "normal" binary operation.
x = new(zone()) BinaryOperation(op, x, y, position); x = new(zone()) BinaryOperation(isolate(), op, x, y, position);
} }
} }
} }
@ -2574,15 +2579,15 @@ Expression* Parser::NewCompareNode(Token::Value op,
bool is_strict = (op == Token::EQ_STRICT); bool is_strict = (op == Token::EQ_STRICT);
Literal* x_literal = x->AsLiteral(); Literal* x_literal = x->AsLiteral();
if (x_literal != NULL && x_literal->IsNull()) { if (x_literal != NULL && x_literal->IsNull()) {
return new(zone()) CompareToNull(is_strict, y); return new(zone()) CompareToNull(isolate(), is_strict, y);
} }
Literal* y_literal = y->AsLiteral(); Literal* y_literal = y->AsLiteral();
if (y_literal != NULL && y_literal->IsNull()) { if (y_literal != NULL && y_literal->IsNull()) {
return new(zone()) CompareToNull(is_strict, x); return new(zone()) CompareToNull(isolate(), is_strict, x);
} }
} }
return new(zone()) CompareOperation(op, x, y, position); return new(zone()) CompareOperation(isolate(), op, x, y, position);
} }
@ -2611,7 +2616,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
// Convert the literal to a boolean condition and negate it. // Convert the literal to a boolean condition and negate it.
bool condition = literal->ToBoolean()->IsTrue(); bool condition = literal->ToBoolean()->IsTrue();
Handle<Object> result(isolate()->heap()->ToBoolean(!condition)); Handle<Object> result(isolate()->heap()->ToBoolean(!condition));
return new(zone()) Literal(result); return NewLiteral(result);
} else if (literal->IsNumber()) { } else if (literal->IsNumber()) {
// Compute some expressions involving only number literals. // Compute some expressions involving only number literals.
double value = literal->Number(); double value = literal->Number();
@ -2638,7 +2643,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
} }
} }
return new(zone()) UnaryOperation(op, expression, position); return new(zone()) UnaryOperation(isolate(), op, expression, position);
} else if (Token::IsCountOp(op)) { } else if (Token::IsCountOp(op)) {
op = Next(); op = Next();
@ -2659,7 +2664,8 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
} }
int position = scanner().location().beg_pos; int position = scanner().location().beg_pos;
return new(zone()) CountOperation(op, return new(zone()) CountOperation(isolate(),
op,
true /* prefix */, true /* prefix */,
expression, expression,
position); position);
@ -2695,7 +2701,8 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
Token::Value next = Next(); Token::Value next = Next();
int position = scanner().location().beg_pos; int position = scanner().location().beg_pos;
expression = expression =
new(zone()) CountOperation(next, new(zone()) CountOperation(isolate(),
next,
false /* postfix */, false /* postfix */,
expression, expression,
position); position);
@ -2721,7 +2728,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
Consume(Token::LBRACK); Consume(Token::LBRACK);
int pos = scanner().location().beg_pos; int pos = scanner().location().beg_pos;
Expression* index = ParseExpression(true, CHECK_OK); Expression* index = ParseExpression(true, CHECK_OK);
result = new(zone()) Property(result, index, pos); result = new(zone()) Property(isolate(), result, index, pos);
Expect(Token::RBRACK, CHECK_OK); Expect(Token::RBRACK, CHECK_OK);
break; break;
} }
@ -2759,7 +2766,10 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
Consume(Token::PERIOD); Consume(Token::PERIOD);
int pos = scanner().location().beg_pos; int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifierName(CHECK_OK); Handle<String> name = ParseIdentifierName(CHECK_OK);
result = new(zone()) Property(result, new(zone()) Literal(name), pos); result = new(zone()) Property(isolate(),
result,
NewLiteral(name),
pos);
if (fni_ != NULL) fni_->PushLiteralName(name); if (fni_ != NULL) fni_->PushLiteralName(name);
break; break;
} }
@ -2795,7 +2805,8 @@ Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) {
if (!stack->is_empty()) { if (!stack->is_empty()) {
int last = stack->pop(); int last = stack->pop();
result = new(zone()) CallNew(result, result = new(zone()) CallNew(isolate(),
result,
new(zone()) ZoneList<Expression*>(0), new(zone()) ZoneList<Expression*>(0),
last); last);
} }
@ -2843,7 +2854,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
Consume(Token::LBRACK); Consume(Token::LBRACK);
int pos = scanner().location().beg_pos; int pos = scanner().location().beg_pos;
Expression* index = ParseExpression(true, CHECK_OK); Expression* index = ParseExpression(true, CHECK_OK);
result = new(zone()) Property(result, index, pos); result = new(zone()) Property(isolate(), result, index, pos);
if (fni_ != NULL) { if (fni_ != NULL) {
if (index->IsPropertyName()) { if (index->IsPropertyName()) {
fni_->PushLiteralName(index->AsLiteral()->AsPropertyName()); fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
@ -2859,7 +2870,10 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
Consume(Token::PERIOD); Consume(Token::PERIOD);
int pos = scanner().location().beg_pos; int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifierName(CHECK_OK); Handle<String> name = ParseIdentifierName(CHECK_OK);
result = new(zone()) Property(result, new(zone()) Literal(name), pos); result = new(zone()) Property(isolate(),
result,
NewLiteral(name),
pos);
if (fni_ != NULL) fni_->PushLiteralName(name); if (fni_ != NULL) fni_->PushLiteralName(name);
break; break;
} }
@ -2868,7 +2882,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack,
// Consume one of the new prefixes (already parsed). // Consume one of the new prefixes (already parsed).
ZoneList<Expression*>* args = ParseArguments(CHECK_OK); ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
int last = stack->pop(); int last = stack->pop();
result = new CallNew(result, args, last); result = new(zone()) CallNew(isolate(), result, args, last);
break; break;
} }
default: default:
@ -2952,23 +2966,26 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
switch (peek()) { switch (peek()) {
case Token::THIS: { case Token::THIS: {
Consume(Token::THIS); Consume(Token::THIS);
result = new(zone()) VariableProxy(top_scope_->receiver()); result = new(zone()) VariableProxy(isolate(), top_scope_->receiver());
break; break;
} }
case Token::NULL_LITERAL: case Token::NULL_LITERAL:
Consume(Token::NULL_LITERAL); Consume(Token::NULL_LITERAL);
result = new(zone()) Literal(isolate()->factory()->null_value()); result = new(zone()) Literal(
isolate(), isolate()->factory()->null_value());
break; break;
case Token::TRUE_LITERAL: case Token::TRUE_LITERAL:
Consume(Token::TRUE_LITERAL); Consume(Token::TRUE_LITERAL);
result = new(zone()) Literal(isolate()->factory()->true_value()); result = new(zone()) Literal(
isolate(), isolate()->factory()->true_value());
break; break;
case Token::FALSE_LITERAL: case Token::FALSE_LITERAL:
Consume(Token::FALSE_LITERAL); Consume(Token::FALSE_LITERAL);
result = new(zone()) Literal(isolate()->factory()->false_value()); result = new(zone()) Literal(
isolate(), isolate()->factory()->false_value());
break; break;
case Token::IDENTIFIER: case Token::IDENTIFIER:
@ -2994,7 +3011,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
case Token::STRING: { case Token::STRING: {
Consume(Token::STRING); Consume(Token::STRING);
Handle<String> symbol = GetSymbol(CHECK_OK); Handle<String> symbol = GetSymbol(CHECK_OK);
result = new(zone()) Literal(symbol); result = NewLiteral(symbol);
if (fni_ != NULL) fni_->PushLiteralName(symbol); if (fni_ != NULL) fni_->PushLiteralName(symbol);
break; break;
} }
@ -3121,8 +3138,8 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
literals->set_map(isolate()->heap()->fixed_cow_array_map()); literals->set_map(isolate()->heap()->fixed_cow_array_map());
} }
return new(zone()) ArrayLiteral(literals, values, return new(zone()) ArrayLiteral(
literal_index, is_simple, depth); isolate(), literals, values, literal_index, is_simple, depth);
} }
@ -3425,7 +3442,6 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode()); ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode());
Expect(Token::LBRACE, CHECK_OK); Expect(Token::LBRACE, CHECK_OK);
Scanner::Location loc = scanner().location();
while (peek() != Token::RBRACE) { while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter(); if (fni_ != NULL) fni_->Enter();
@ -3467,7 +3483,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
} }
// Failed to parse as get/set property, so it's just a property // Failed to parse as get/set property, so it's just a property
// called "get" or "set". // called "get" or "set".
key = new(zone()) Literal(id); key = NewLiteral(id);
break; break;
} }
case Token::STRING: { case Token::STRING: {
@ -3479,7 +3495,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
key = NewNumberLiteral(index); key = NewNumberLiteral(index);
break; break;
} }
key = new(zone()) Literal(string); key = NewLiteral(string);
break; break;
} }
case Token::NUMBER: { case Token::NUMBER: {
@ -3495,7 +3511,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
if (Token::IsKeyword(next)) { if (Token::IsKeyword(next)) {
Consume(next); Consume(next);
Handle<String> string = GetSymbol(CHECK_OK); Handle<String> string = GetSymbol(CHECK_OK);
key = new(zone()) Literal(string); key = NewLiteral(string);
} else { } else {
// Unexpected token. // Unexpected token.
Token::Value next = Next(); Token::Value next = Next();
@ -3548,13 +3564,14 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
&is_simple, &is_simple,
&fast_elements, &fast_elements,
&depth); &depth);
return new(zone()) ObjectLiteral(constant_properties, return new(zone()) ObjectLiteral(isolate(),
properties, constant_properties,
literal_index, properties,
is_simple, literal_index,
fast_elements, is_simple,
depth, fast_elements,
has_function); depth,
has_function);
} }
@ -3573,7 +3590,8 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
Handle<String> js_flags = NextLiteralString(TENURED); Handle<String> js_flags = NextLiteralString(TENURED);
Next(); Next();
return new(zone()) RegExpLiteral(js_pattern, js_flags, literal_index); return new(zone()) RegExpLiteral(
isolate(), js_pattern, js_flags, literal_index);
} }
@ -3690,9 +3708,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
top_scope_->NewUnresolved(function_name, inside_with()); top_scope_->NewUnresolved(function_name, inside_with());
fproxy->BindTo(fvar); fproxy->BindTo(fvar);
body->Add(new(zone()) ExpressionStatement( body->Add(new(zone()) ExpressionStatement(
new(zone()) Assignment(Token::INIT_CONST, fproxy, new(zone()) Assignment(isolate(),
new(zone()) ThisFunction(), Token::INIT_CONST,
RelocInfo::kNoPosition))); fproxy,
new(zone()) ThisFunction(isolate()),
RelocInfo::kNoPosition)));
} }
// Determine if the function will be lazily compiled. The mode can // Determine if the function will be lazily compiled. The mode can
@ -3782,7 +3802,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
} }
FunctionLiteral* function_literal = FunctionLiteral* function_literal =
new(zone()) FunctionLiteral(name, new(zone()) FunctionLiteral(isolate(),
name,
scope, scope,
body, body,
materialized_literal_count, materialized_literal_count,
@ -3843,7 +3864,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
} }
// We have a valid intrinsics call or a call to a builtin. // We have a valid intrinsics call or a call to a builtin.
return new(zone()) CallRuntime(name, function, args); return new(zone()) CallRuntime(isolate(), name, function, args);
} }
@ -3899,12 +3920,12 @@ void Parser::ExpectSemicolon(bool* ok) {
Literal* Parser::GetLiteralUndefined() { Literal* Parser::GetLiteralUndefined() {
return new(zone()) Literal(isolate()->factory()->undefined_value()); return NewLiteral(isolate()->factory()->undefined_value());
} }
Literal* Parser::GetLiteralTheHole() { Literal* Parser::GetLiteralTheHole() {
return new(zone()) Literal(isolate()->factory()->the_hole_value()); return NewLiteral(isolate()->factory()->the_hole_value());
} }
@ -4060,7 +4081,7 @@ void Parser::RegisterTargetUse(Label* target, Target* stop) {
Literal* Parser::NewNumberLiteral(double number) { Literal* Parser::NewNumberLiteral(double number) {
return new(zone()) Literal(isolate()->factory()->NewNumber(number, TENURED)); return NewLiteral(isolate()->factory()->NewNumber(number, TENURED));
} }
@ -4107,10 +4128,15 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
TENURED); TENURED);
ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2); ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2);
args->Add(new(zone()) Literal(type)); args->Add(NewLiteral(type));
args->Add(new(zone()) Literal(array)); args->Add(NewLiteral(array));
return new(zone()) Throw(new(zone()) CallRuntime(constructor, NULL, args), CallRuntime* call_constructor = new(zone()) CallRuntime(isolate(),
scanner().location().beg_pos); constructor,
NULL,
args);
return new(zone()) Throw(isolate(),
call_constructor,
scanner().location().beg_pos);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

5
deps/v8/src/parser.h

@ -668,9 +668,12 @@ class Parser {
Expression* NewCall(Expression* expression, Expression* NewCall(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
int pos) { int pos) {
return new Call(expression, arguments, pos); return new(zone()) Call(isolate(), expression, arguments, pos);
} }
inline Literal* NewLiteral(Handle<Object> handle) {
return new(zone()) Literal(isolate(), handle);
}
// Create a number literal. // Create a number literal.
Literal* NewNumberLiteral(double value); Literal* NewNumberLiteral(double value);

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

@ -734,6 +734,7 @@ class LinuxMutex : public Mutex {
ASSERT(result == 0); ASSERT(result == 0);
result = pthread_mutex_init(&mutex_, &attrs); result = pthread_mutex_init(&mutex_, &attrs);
ASSERT(result == 0); ASSERT(result == 0);
USE(result);
} }
virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); } virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }

5
deps/v8/src/platform-nullos.cc

@ -217,6 +217,11 @@ void OS::Free(void* buf, const size_t length) {
} }
void OS::Guard(void* address, const size_t size) {
UNIMPLEMENTED();
}
void OS::Sleep(int milliseconds) { void OS::Sleep(int milliseconds) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }

9
deps/v8/src/platform-posix.cc

@ -33,6 +33,7 @@
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <sys/mman.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/time.h> #include <sys/time.h>
@ -43,6 +44,8 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <netdb.h> #include <netdb.h>
#undef MAP_TYPE
#if defined(ANDROID) #if defined(ANDROID)
#define LOG_TAG "v8" #define LOG_TAG "v8"
#include <utils/Log.h> // LOG_PRI_VA #include <utils/Log.h> // LOG_PRI_VA
@ -67,6 +70,12 @@ intptr_t OS::MaxVirtualMemory() {
} }
// Create guard pages.
void OS::Guard(void* address, const size_t size) {
mprotect(address, size, PROT_NONE);
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Math functions // Math functions

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

@ -957,6 +957,12 @@ void OS::Free(void* address, const size_t size) {
} }
void OS::Guard(void* address, const size_t size) {
DWORD oldprotect;
VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
}
void OS::Sleep(int milliseconds) { void OS::Sleep(int milliseconds) {
::Sleep(milliseconds); ::Sleep(milliseconds);
} }

4
deps/v8/src/platform.h

@ -206,6 +206,10 @@ class OS {
size_t* allocated, size_t* allocated,
bool is_executable); bool is_executable);
static void Free(void* address, const size_t size); static void Free(void* address, const size_t size);
// Assign memory as a guard page so that access will cause an exception.
static void Guard(void* address, const size_t size);
// Get the Alignment guaranteed by Allocate(). // Get the Alignment guaranteed by Allocate().
static size_t AllocateAlignment(); static size_t AllocateAlignment();

16
deps/v8/src/rewriter.cc

@ -66,9 +66,13 @@ class Processor: public AstVisitor {
Expression* SetResult(Expression* value) { Expression* SetResult(Expression* value) {
result_assigned_ = true; result_assigned_ = true;
VariableProxy* result_proxy = new VariableProxy(result_); Zone* zone = isolate()->zone();
return new Assignment(Token::ASSIGN, result_proxy, value, VariableProxy* result_proxy = new(zone) VariableProxy(isolate(), result_);
RelocInfo::kNoPosition); return new(zone) Assignment(isolate(),
Token::ASSIGN,
result_proxy,
value,
RelocInfo::kNoPosition);
} }
// Node visitors. // Node visitors.
@ -229,8 +233,10 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
if (processor.HasStackOverflow()) return false; if (processor.HasStackOverflow()) return false;
if (processor.result_assigned()) { if (processor.result_assigned()) {
VariableProxy* result_proxy = new VariableProxy(result); Isolate* isolate = info->isolate();
body->Add(new ReturnStatement(result_proxy)); Zone* zone = isolate->zone();
VariableProxy* result_proxy = new(zone) VariableProxy(isolate, result);
body->Add(new(zone) ReturnStatement(result_proxy));
} }
} }

273
deps/v8/src/runtime.cc

@ -615,6 +615,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
} }
RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSProxy, proxy, args[0]);
proxy->Fix();
return proxy;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) { RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
@ -3872,7 +3880,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
|| result.type() == CONSTANT_FUNCTION)) { || result.type() == CONSTANT_FUNCTION)) {
Object* ok; Object* ok;
{ MaybeObject* maybe_ok = { MaybeObject* maybe_ok =
obj->DeleteProperty(name, JSObject::NORMAL_DELETION); obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
if (!maybe_ok->ToObject(&ok)) return maybe_ok; if (!maybe_ok->ToObject(&ok)) return maybe_ok;
} }
} }
@ -4126,24 +4134,25 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
Handle<JSObject> js_object, Handle<JSReceiver> receiver,
Handle<Object> key) { Handle<Object> key) {
HandleScope scope(isolate); HandleScope scope(isolate);
// Check if the given key is an array index. // Check if the given key is an array index.
uint32_t index; uint32_t index;
if (key->ToArrayIndex(&index)) { if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
// In Firefox/SpiderMonkey, Safari and Opera you can access the // In Firefox/SpiderMonkey, Safari and Opera you can access the
// characters of a string using [] notation. In the case of a // characters of a string using [] notation. In the case of a
// String object we just need to redirect the deletion to the // String object we just need to redirect the deletion to the
// underlying string if the index is in range. Since the // underlying string if the index is in range. Since the
// underlying string does nothing with the deletion, we can ignore // underlying string does nothing with the deletion, we can ignore
// such deletions. // such deletions.
if (js_object->IsStringObjectWithCharacterAt(index)) { if (receiver->IsStringObjectWithCharacterAt(index)) {
return isolate->heap()->true_value(); return isolate->heap()->true_value();
} }
return js_object->DeleteElement(index, JSObject::FORCE_DELETION); return JSObject::cast(*receiver)->DeleteElement(
index, JSReceiver::FORCE_DELETION);
} }
Handle<String> key_string; Handle<String> key_string;
@ -4158,7 +4167,7 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
} }
key_string->TryFlatten(); key_string->TryFlatten();
return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION); return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
} }
@ -4237,12 +4246,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 3); ASSERT(args.length() == 3);
CONVERT_CHECKED(JSObject, object, args[0]); CONVERT_CHECKED(JSReceiver, object, args[0]);
CONVERT_CHECKED(String, key, args[1]); CONVERT_CHECKED(String, key, args[1]);
CONVERT_SMI_ARG_CHECKED(strict, 2); CONVERT_SMI_ARG_CHECKED(strict, 2);
return object->DeleteProperty(key, (strict == kStrictMode) return object->DeleteProperty(key, (strict == kStrictMode)
? JSObject::STRICT_DELETION ? JSReceiver::STRICT_DELETION
: JSObject::NORMAL_DELETION); : JSReceiver::NORMAL_DELETION);
} }
@ -4306,11 +4315,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
NoHandleAllocation na; NoHandleAllocation na;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
// Only JS objects can have properties. // Only JS receivers can have properties.
if (args[0]->IsJSObject()) { if (args[0]->IsJSReceiver()) {
JSObject* object = JSObject::cast(args[0]); JSReceiver* receiver = JSReceiver::cast(args[0]);
CONVERT_CHECKED(String, key, args[1]); CONVERT_CHECKED(String, key, args[1]);
if (object->HasProperty(key)) return isolate->heap()->true_value(); if (receiver->HasProperty(key)) return isolate->heap()->true_value();
} }
return isolate->heap()->false_value(); return isolate->heap()->false_value();
} }
@ -8198,9 +8207,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
// index is non-negative. // index is non-negative.
Handle<JSObject> object = Handle<JSObject>::cast(holder); Handle<JSObject> object = Handle<JSObject>::cast(holder);
if (index >= 0) { if (index >= 0) {
return object->DeleteElement(index, JSObject::NORMAL_DELETION); return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
} else { } else {
return object->DeleteProperty(*name, JSObject::NORMAL_DELETION); return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
} }
} }
@ -9976,6 +9985,71 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
} }
class FrameInspector {
public:
FrameInspector(JavaScriptFrame* frame,
int inlined_frame_index,
Isolate* isolate)
: frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
// Calculate the deoptimized frame.
if (frame->is_optimized()) {
deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
frame, inlined_frame_index, isolate);
}
has_adapted_arguments_ = frame_->has_adapted_arguments();
is_optimized_ = frame_->is_optimized();
}
~FrameInspector() {
// Get rid of the calculated deoptimized frame if any.
if (deoptimized_frame_ != NULL) {
Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
isolate_);
}
}
int GetParametersCount() {
return is_optimized_
? deoptimized_frame_->parameters_count()
: frame_->ComputeParametersCount();
}
int expression_count() { return deoptimized_frame_->expression_count(); }
Object* GetFunction() {
return is_optimized_
? deoptimized_frame_->GetFunction()
: frame_->function();
}
Object* GetParameter(int index) {
return is_optimized_
? deoptimized_frame_->GetParameter(index)
: frame_->GetParameter(index);
}
Object* GetExpression(int index) {
return is_optimized_
? deoptimized_frame_->GetExpression(index)
: frame_->GetExpression(index);
}
// To inspect all the provided arguments the frame might need to be
// replaced with the arguments frame.
void SetArgumentsFrame(JavaScriptFrame* frame) {
ASSERT(has_adapted_arguments_);
frame_ = frame;
is_optimized_ = frame_->is_optimized();
ASSERT(!is_optimized_);
}
private:
JavaScriptFrame* frame_;
DeoptimizedFrameInfo* deoptimized_frame_;
Isolate* isolate_;
bool is_optimized_;
bool has_adapted_arguments_;
DISALLOW_COPY_AND_ASSIGN(FrameInspector);
};
static const int kFrameDetailsFrameIdIndex = 0; static const int kFrameDetailsFrameIdIndex = 0;
static const int kFrameDetailsReceiverIndex = 1; static const int kFrameDetailsReceiverIndex = 1;
static const int kFrameDetailsFunctionIndex = 2; static const int kFrameDetailsFunctionIndex = 2;
@ -10024,8 +10098,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
return heap->undefined_value(); return heap->undefined_value();
} }
int deoptimized_frame_index = -1; // Frame index in optimized frame. int inlined_frame_index = 0; // Inlined frame index in optimized frame.
DeoptimizedFrameInfo* deoptimized_frame = NULL;
int count = 0; int count = 0;
JavaScriptFrameIterator it(isolate, id); JavaScriptFrameIterator it(isolate, id);
@ -10036,13 +10109,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
if (it.done()) return heap->undefined_value(); if (it.done()) return heap->undefined_value();
if (it.frame()->is_optimized()) { if (it.frame()->is_optimized()) {
deoptimized_frame_index = inlined_frame_index =
it.frame()->GetInlineCount() - (index - count) - 1; it.frame()->GetInlineCount() - (index - count) - 1;
deoptimized_frame = Deoptimizer::DebuggerInspectableFrame(
it.frame(),
deoptimized_frame_index,
isolate);
} }
FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
// Traverse the saved contexts chain to find the active context for the // Traverse the saved contexts chain to find the active context for the
// selected frame. // selected frame.
@ -10061,12 +10131,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// Check for constructor frame. Inlined frames cannot be construct calls. // Check for constructor frame. Inlined frames cannot be construct calls.
bool inlined_frame = bool inlined_frame =
it.frame()->is_optimized() && deoptimized_frame_index != 0; it.frame()->is_optimized() && inlined_frame_index != 0;
bool constructor = !inlined_frame && it.frame()->IsConstructor(); bool constructor = !inlined_frame && it.frame()->IsConstructor();
// Get scope info and read from it for local variable information. // Get scope info and read from it for local variable information.
Handle<JSFunction> function(JSFunction::cast(it.frame()->function())); Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info()); Handle<SharedFunctionInfo> shared(function->shared());
Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ASSERT(*scope_info != SerializedScopeInfo::Empty()); ASSERT(*scope_info != SerializedScopeInfo::Empty());
ScopeInfo<> info(*scope_info); ScopeInfo<> info(*scope_info);
@ -10083,14 +10154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
for (; i < info.number_of_stack_slots(); ++i) { for (; i < info.number_of_stack_slots(); ++i) {
// Use the value from the stack. // Use the value from the stack.
locals->set(i * 2, *info.LocalName(i)); locals->set(i * 2, *info.LocalName(i));
if (it.frame()->is_optimized()) { locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
// Get the value from the deoptimized frame.
locals->set(i * 2 + 1,
deoptimized_frame->GetExpression(i));
} else {
// Get the value from the stack.
locals->set(i * 2 + 1, it.frame()->GetExpression(i));
}
} }
if (i < info.NumberOfLocals()) { if (i < info.NumberOfLocals()) {
// Get the context containing declarations. // Get the context containing declarations.
@ -10147,18 +10211,22 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// the provided parameters whereas the function frame always have the number // the provided parameters whereas the function frame always have the number
// of arguments matching the functions parameters. The rest of the // of arguments matching the functions parameters. The rest of the
// information (except for what is collected above) is the same. // information (except for what is collected above) is the same.
it.AdvanceToArgumentsFrame(); if (it.frame()->has_adapted_arguments()) {
it.AdvanceToArgumentsFrame();
frame_inspector.SetArgumentsFrame(it.frame());
}
// Find the number of arguments to fill. At least fill the number of // Find the number of arguments to fill. At least fill the number of
// parameters for the function and fill more if more parameters are provided. // parameters for the function and fill more if more parameters are provided.
int argument_count = info.number_of_parameters(); int argument_count = info.number_of_parameters();
if (argument_count < frame_inspector.GetParametersCount()) {
argument_count = frame_inspector.GetParametersCount();
}
#ifdef DEBUG
if (it.frame()->is_optimized()) { if (it.frame()->is_optimized()) {
ASSERT_EQ(argument_count, deoptimized_frame->parameters_count()); ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
} else {
if (argument_count < it.frame()->ComputeParametersCount()) {
argument_count = it.frame()->ComputeParametersCount();
}
} }
#endif
// Calculate the size of the result. // Calculate the size of the result.
int details_size = kFrameDetailsFirstDynamicIndex + int details_size = kFrameDetailsFirstDynamicIndex +
@ -10170,13 +10238,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
details->set(kFrameDetailsFrameIdIndex, *frame_id); details->set(kFrameDetailsFrameIdIndex, *frame_id);
// Add the function (same as in function frame). // Add the function (same as in function frame).
if (it.frame()->is_optimized()) { details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
// Get the function from the deoptimized frame.
details->set(kFrameDetailsFunctionIndex, deoptimized_frame->GetFunction());
} else {
// Get the function from the stack.
details->set(kFrameDetailsFunctionIndex, it.frame()->function());
}
// Add the arguments count. // Add the arguments count.
details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
@ -10208,9 +10270,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
} }
if (it.frame()->is_optimized()) { if (it.frame()->is_optimized()) {
flags |= 1 << 1; flags |= 1 << 1;
if (deoptimized_frame_index > 0) { flags |= inlined_frame_index << 2;
flags |= 1 << 2;
}
} }
details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
@ -10227,16 +10287,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
} }
// Parameter value. // Parameter value.
if (it.frame()->is_optimized()) { if (i < it.frame()->ComputeParametersCount()) {
// Get the value from the deoptimized frame. // Get the value from the stack.
details->set(details_index++, deoptimized_frame->GetParameter(i)); details->set(details_index++, frame_inspector.GetParameter(i));
} else { } else {
if (i < it.frame()->ComputeParametersCount()) { details->set(details_index++, heap->undefined_value());
// Get the value from the stack.
details->set(details_index++, it.frame()->GetParameter(i));
} else {
details->set(details_index++, heap->undefined_value());
}
} }
} }
@ -10254,10 +10309,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
// THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
// THE FRAME ITERATOR TO WRAP THE RECEIVER. // THE FRAME ITERATOR TO WRAP THE RECEIVER.
Handle<Object> receiver(it.frame()->receiver(), isolate); Handle<Object> receiver(it.frame()->receiver(), isolate);
if (!receiver->IsJSObject()) { if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
// If the receiver is NOT a JSObject we have hit an optimization // If the receiver is not a JSObject and the function is not a
// where a value object is not converted into a wrapped JS objects. // builtin or strict-mode we have hit an optimization where a
// To hide this optimization from the debugger, we wrap the receiver // value object is not converted into a wrapped JS objects. To
// hide this optimization from the debugger, we wrap the receiver
// by creating correct wrapper object based on the calling frame's // by creating correct wrapper object based on the calling frame's
// global context. // global context.
it.Advance(); it.Advance();
@ -10268,12 +10324,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
} }
details->set(kFrameDetailsReceiverIndex, *receiver); details->set(kFrameDetailsReceiverIndex, *receiver);
// Get rid of the calculated deoptimized frame if any.
if (deoptimized_frame != NULL) {
Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame,
isolate);
}
ASSERT_EQ(details_size, details_index); ASSERT_EQ(details_size, details_index);
return *isolate->factory()->NewJSArrayWithElements(details); return *isolate->factory()->NewJSArrayWithElements(details);
} }
@ -10309,12 +10359,15 @@ static bool CopyContextLocalsToScopeObject(
// Create a plain JSObject which materializes the local scope for the specified // Create a plain JSObject which materializes the local scope for the specified
// frame. // frame.
static Handle<JSObject> MaterializeLocalScope(Isolate* isolate, static Handle<JSObject> MaterializeLocalScope(
JavaScriptFrame* frame) { Isolate* isolate,
JavaScriptFrame* frame,
int inlined_frame_index) {
Handle<JSFunction> function(JSFunction::cast(frame->function())); Handle<JSFunction> function(JSFunction::cast(frame->function()));
Handle<SharedFunctionInfo> shared(function->shared()); Handle<SharedFunctionInfo> shared(function->shared());
Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info()); Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
ScopeInfo<> scope_info(*serialized_scope_info); ScopeInfo<> scope_info(*serialized_scope_info);
FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
// Allocate and initialize a JSObject with all the arguments, stack locals // Allocate and initialize a JSObject with all the arguments, stack locals
// heap locals and extension properties of the debugged function. // heap locals and extension properties of the debugged function.
@ -10327,7 +10380,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
isolate, isolate,
SetProperty(local_scope, SetProperty(local_scope,
scope_info.parameter_name(i), scope_info.parameter_name(i),
Handle<Object>(frame->GetParameter(i), isolate), Handle<Object>(frame_inspector.GetParameter(i)),
NONE, NONE,
kNonStrictMode), kNonStrictMode),
Handle<JSObject>()); Handle<JSObject>());
@ -10339,7 +10392,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
isolate, isolate,
SetProperty(local_scope, SetProperty(local_scope,
scope_info.stack_slot_name(i), scope_info.stack_slot_name(i),
Handle<Object>(frame->GetExpression(i), isolate), Handle<Object>(frame_inspector.GetExpression(i)),
NONE, NONE,
kNonStrictMode), kNonStrictMode),
Handle<JSObject>()); Handle<JSObject>());
@ -10459,9 +10512,12 @@ class ScopeIterator {
ScopeTypeCatch ScopeTypeCatch
}; };
ScopeIterator(Isolate* isolate, JavaScriptFrame* frame) ScopeIterator(Isolate* isolate,
JavaScriptFrame* frame,
int inlined_frame_index)
: isolate_(isolate), : isolate_(isolate),
frame_(frame), frame_(frame),
inlined_frame_index_(inlined_frame_index),
function_(JSFunction::cast(frame->function())), function_(JSFunction::cast(frame->function())),
context_(Context::cast(frame->context())), context_(Context::cast(frame->context())),
local_done_(false), local_done_(false),
@ -10546,7 +10602,7 @@ class ScopeIterator {
return Handle<JSObject>(CurrentContext()->global()); return Handle<JSObject>(CurrentContext()->global());
case ScopeIterator::ScopeTypeLocal: case ScopeIterator::ScopeTypeLocal:
// Materialize the content of the local scope into a JSObject. // Materialize the content of the local scope into a JSObject.
return MaterializeLocalScope(isolate_, frame_); return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
case ScopeIterator::ScopeTypeWith: case ScopeIterator::ScopeTypeWith:
// Return the with object. // Return the with object.
return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
@ -10626,6 +10682,7 @@ class ScopeIterator {
private: private:
Isolate* isolate_; Isolate* isolate_;
JavaScriptFrame* frame_; JavaScriptFrame* frame_;
int inlined_frame_index_;
Handle<JSFunction> function_; Handle<JSFunction> function_;
Handle<Context> context_; Handle<Context> context_;
bool local_done_; bool local_done_;
@ -10654,7 +10711,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
// Count the visible scopes. // Count the visible scopes.
int n = 0; int n = 0;
for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) { for (ScopeIterator it(isolate, frame, 0);
!it.Done();
it.Next()) {
n++; n++;
} }
@ -10669,14 +10728,15 @@ static const int kScopeDetailsSize = 2;
// Return an array with scope details // Return an array with scope details
// args[0]: number: break id // args[0]: number: break id
// args[1]: number: frame index // args[1]: number: frame index
// args[2]: number: scope index // args[2]: number: inlined frame index
// args[3]: number: scope index
// //
// The array returned contains the following information: // The array returned contains the following information:
// 0: Scope type // 0: Scope type
// 1: Scope object // 1: Scope object
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 3); ASSERT(args.length() == 4);
// Check arguments. // Check arguments.
Object* check; Object* check;
@ -10685,7 +10745,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
if (!maybe_check->ToObject(&check)) return maybe_check; if (!maybe_check->ToObject(&check)) return maybe_check;
} }
CONVERT_CHECKED(Smi, wrapped_id, args[1]); CONVERT_CHECKED(Smi, wrapped_id, args[1]);
CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]); CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
// Get the frame where the debugging is performed. // Get the frame where the debugging is performed.
StackFrame::Id id = UnwrapFrameId(wrapped_id); StackFrame::Id id = UnwrapFrameId(wrapped_id);
@ -10694,7 +10755,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
// Find the requested scope. // Find the requested scope.
int n = 0; int n = 0;
ScopeIterator it(isolate, frame); ScopeIterator it(isolate, frame, inlined_frame_index);
for (; !it.Done() && n < index; it.Next()) { for (; !it.Done() && n < index; it.Next()) {
n++; n++;
} }
@ -10724,7 +10785,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
// Print the scopes for the top frame. // Print the scopes for the top frame.
StackFrameLocator locator; StackFrameLocator locator;
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) { for (ScopeIterator it(isolate, frame, 0);
!it.Done();
it.Next()) {
it.DebugPrint(); it.DebugPrint();
} }
#endif #endif
@ -11117,6 +11180,7 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate,
// Runtime_DebugEvaluate. // Runtime_DebugEvaluate.
static Handle<Object> GetArgumentsObject(Isolate* isolate, static Handle<Object> GetArgumentsObject(Isolate* isolate,
JavaScriptFrame* frame, JavaScriptFrame* frame,
int inlined_frame_index,
Handle<JSFunction> function, Handle<JSFunction> function,
Handle<SerializedScopeInfo> scope_info, Handle<SerializedScopeInfo> scope_info,
const ScopeInfo<>* sinfo, const ScopeInfo<>* sinfo,
@ -11128,6 +11192,7 @@ static Handle<Object> GetArgumentsObject(Isolate* isolate,
if (sinfo->number_of_stack_slots() > 0) { if (sinfo->number_of_stack_slots() > 0) {
index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol()); index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
if (index != -1) { if (index != -1) {
CHECK(false);
return Handle<Object>(frame->GetExpression(index), isolate); return Handle<Object>(frame->GetExpression(index), isolate);
} }
} }
@ -11140,7 +11205,9 @@ static Handle<Object> GetArgumentsObject(Isolate* isolate,
} }
} }
const int length = frame->ComputeParametersCount(); FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
int length = frame_inspector.GetParametersCount();
Handle<JSObject> arguments = Handle<JSObject> arguments =
isolate->factory()->NewArgumentsObject(function, length); isolate->factory()->NewArgumentsObject(function, length);
Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
@ -11148,7 +11215,7 @@ static Handle<Object> GetArgumentsObject(Isolate* isolate,
AssertNoAllocation no_gc; AssertNoAllocation no_gc;
WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
array->set(i, frame->GetParameter(i), mode); array->set(i, frame_inspector.GetParameter(i), mode);
} }
arguments->set_elements(*array); arguments->set_elements(*array);
return arguments; return arguments;
@ -11175,7 +11242,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
// Check the execution state and decode arguments frame and source to be // Check the execution state and decode arguments frame and source to be
// evaluated. // evaluated.
ASSERT(args.length() == 5); ASSERT(args.length() == 6);
Object* check_result; Object* check_result;
{ MaybeObject* maybe_check_result = Runtime_CheckExecutionState( { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
RUNTIME_ARGUMENTS(isolate, args)); RUNTIME_ARGUMENTS(isolate, args));
@ -11184,9 +11251,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
} }
} }
CONVERT_CHECKED(Smi, wrapped_id, args[1]); CONVERT_CHECKED(Smi, wrapped_id, args[1]);
CONVERT_ARG_CHECKED(String, source, 2); CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
CONVERT_BOOLEAN_CHECKED(disable_break, args[3]); CONVERT_ARG_CHECKED(String, source, 3);
Handle<Object> additional_context(args[4]); CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
Handle<Object> additional_context(args[5]);
// Handle the processing of break. // Handle the processing of break.
DisableBreak disable_break_save(disable_break); DisableBreak disable_break_save(disable_break);
@ -11226,7 +11294,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
#endif #endif
// Materialize the content of the local scope into a JSObject. // Materialize the content of the local scope into a JSObject.
Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame); Handle<JSObject> local_scope = MaterializeLocalScope(
isolate, frame, inlined_frame_index);
RETURN_IF_EMPTY_HANDLE(isolate, local_scope); RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
// Allocate a new context for the debug evaluation and set the extension // Allocate a new context for the debug evaluation and set the extension
@ -11275,7 +11344,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
&has_pending_exception); &has_pending_exception);
if (has_pending_exception) return Failure::Exception(); if (has_pending_exception) return Failure::Exception();
Handle<Object> arguments = GetArgumentsObject(isolate, frame, Handle<Object> arguments = GetArgumentsObject(isolate,
frame, inlined_frame_index,
function, scope_info, function, scope_info,
&sinfo, function_context); &sinfo, function_context);
@ -12214,8 +12284,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
// call to this function is encountered it is skipped. The seen_caller // call to this function is encountered it is skipped. The seen_caller
// in/out parameter is used to remember if the caller has been seen // in/out parameter is used to remember if the caller has been seen
// yet. // yet.
static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller, static bool ShowFrameInStackTrace(StackFrame* raw_frame,
bool* seen_caller) { Object* caller,
bool* seen_caller) {
// Only display JS frames. // Only display JS frames.
if (!raw_frame->is_java_script()) if (!raw_frame->is_java_script())
return false; return false;
@ -12228,11 +12299,25 @@ static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
*seen_caller = true; *seen_caller = true;
return false; return false;
} }
// Skip all frames until we've seen the caller. Also, skip the most // Skip all frames until we've seen the caller.
// obvious builtin calls. Some builtin calls (such as Number.ADD if (!(*seen_caller)) return false;
// which is invoked using 'call') are very difficult to recognize // Also, skip the most obvious builtin calls. We recognize builtins
// so we're leaving them in for now. // as (1) functions called with the builtins object as the receiver and
return *seen_caller && !frame->receiver()->IsJSBuiltinsObject(); // as (2) functions from native scripts called with undefined as the
// receiver (direct calls to helper functions in the builtins
// code). Some builtin calls (such as Number.ADD which is invoked
// using 'call') are very difficult to recognize so we're leaving
// them in for now.
if (frame->receiver()->IsJSBuiltinsObject()) {
return false;
}
JSFunction* fun = JSFunction::cast(raw_fun);
Object* raw_script = fun->shared()->script();
if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
int script_type = Script::cast(raw_script)->type()->value();
return script_type != Script::TYPE_NATIVE;
}
return true;
} }

7
deps/v8/src/runtime.h

@ -284,6 +284,7 @@ namespace internal {
F(CreateJSProxy, 2, 1) \ F(CreateJSProxy, 2, 1) \
F(IsJSProxy, 1, 1) \ F(IsJSProxy, 1, 1) \
F(GetHandler, 1, 1) \ F(GetHandler, 1, 1) \
F(Fix, 1, 1) \
\ \
/* Statements */ \ /* Statements */ \
F(NewClosure, 3, 1) \ F(NewClosure, 3, 1) \
@ -372,7 +373,7 @@ namespace internal {
F(GetFrameCount, 1, 1) \ F(GetFrameCount, 1, 1) \
F(GetFrameDetails, 2, 1) \ F(GetFrameDetails, 2, 1) \
F(GetScopeCount, 2, 1) \ F(GetScopeCount, 2, 1) \
F(GetScopeDetails, 3, 1) \ F(GetScopeDetails, 4, 1) \
F(DebugPrintScopes, 0, 1) \ F(DebugPrintScopes, 0, 1) \
F(GetThreadCount, 1, 1) \ F(GetThreadCount, 1, 1) \
F(GetThreadDetails, 2, 1) \ F(GetThreadDetails, 2, 1) \
@ -385,7 +386,7 @@ namespace internal {
F(IsBreakOnException, 1, 1) \ F(IsBreakOnException, 1, 1) \
F(PrepareStep, 3, 1) \ F(PrepareStep, 3, 1) \
F(ClearStepping, 0, 1) \ F(ClearStepping, 0, 1) \
F(DebugEvaluate, 5, 1) \ F(DebugEvaluate, 6, 1) \
F(DebugEvaluateGlobal, 4, 1) \ F(DebugEvaluateGlobal, 4, 1) \
F(DebugGetLoadedScripts, 0, 1) \ F(DebugGetLoadedScripts, 0, 1) \
F(DebugReferencedBy, 3, 1) \ F(DebugReferencedBy, 3, 1) \
@ -636,7 +637,7 @@ class Runtime : public AllStatic {
MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty( MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty(
Isolate* isolate, Isolate* isolate,
Handle<JSObject> object, Handle<JSReceiver> object,
Handle<Object> key); Handle<Object> key);
MUST_USE_RESULT static MaybeObject* GetObjectProperty( MUST_USE_RESULT static MaybeObject* GetObjectProperty(

3
deps/v8/src/runtime.js

@ -354,7 +354,8 @@ function IN(x) {
if (!IS_SPEC_OBJECT(x)) { if (!IS_SPEC_OBJECT(x)) {
throw %MakeTypeError('invalid_in_operator_use', [this, x]); throw %MakeTypeError('invalid_in_operator_use', [this, x]);
} }
return %_IsNonNegativeSmi(this) ? %HasElement(x, this) : %HasProperty(x, %ToString(this)); return %_IsNonNegativeSmi(this) && !%IsJSProxy(x) ?
%HasElement(x, this) : %HasProperty(x, %ToString(this));
} }

89
deps/v8/src/scopes.cc

@ -116,25 +116,27 @@ Variable* VariableMap::Lookup(Handle<String> name) {
// Dummy constructor // Dummy constructor
Scope::Scope(Type type) Scope::Scope(Type type)
: inner_scopes_(0), : isolate_(Isolate::Current()),
variables_(false), inner_scopes_(0),
temps_(0), variables_(false),
params_(0), temps_(0),
unresolved_(0), params_(0),
decls_(0), unresolved_(0),
already_resolved_(false) { decls_(0),
already_resolved_(false) {
SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null()); SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null());
} }
Scope::Scope(Scope* outer_scope, Type type) Scope::Scope(Scope* outer_scope, Type type)
: inner_scopes_(4), : isolate_(Isolate::Current()),
variables_(), inner_scopes_(4),
temps_(4), variables_(),
params_(4), temps_(4),
unresolved_(16), params_(4),
decls_(4), unresolved_(16),
already_resolved_(false) { decls_(4),
already_resolved_(false) {
SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null()); SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null());
// At some point we might want to provide outer scopes to // At some point we might want to provide outer scopes to
// eval scopes (by walking the stack and reading the scope info). // eval scopes (by walking the stack and reading the scope info).
@ -145,13 +147,14 @@ Scope::Scope(Scope* outer_scope, Type type)
Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info) Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
: inner_scopes_(4), : isolate_(Isolate::Current()),
variables_(), inner_scopes_(4),
temps_(4), variables_(),
params_(4), temps_(4),
unresolved_(16), params_(4),
decls_(4), unresolved_(16),
already_resolved_(true) { decls_(4),
already_resolved_(true) {
ASSERT(!scope_info.is_null()); ASSERT(!scope_info.is_null());
SetDefaults(FUNCTION_SCOPE, NULL, scope_info); SetDefaults(FUNCTION_SCOPE, NULL, scope_info);
if (scope_info->HasHeapAllocatedLocals()) { if (scope_info->HasHeapAllocatedLocals()) {
@ -162,7 +165,8 @@ Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name) Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name)
: inner_scopes_(1), : isolate_(Isolate::Current()),
inner_scopes_(1),
variables_(), variables_(),
temps_(0), temps_(0),
params_(0), params_(0),
@ -186,7 +190,7 @@ void Scope::SetDefaults(Type type,
Handle<SerializedScopeInfo> scope_info) { Handle<SerializedScopeInfo> scope_info) {
outer_scope_ = outer_scope; outer_scope_ = outer_scope;
type_ = type; type_ = type;
scope_name_ = FACTORY->empty_symbol(); scope_name_ = isolate_->factory()->empty_symbol();
dynamics_ = NULL; dynamics_ = NULL;
receiver_ = NULL; receiver_ = NULL;
function_ = NULL; function_ = NULL;
@ -295,9 +299,12 @@ void Scope::Initialize(bool inside_with) {
receiver_ = outer_scope()->receiver(); receiver_ = outer_scope()->receiver();
} else { } else {
Variable* var = Variable* var =
variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR, variables_.Declare(this,
false, Variable::THIS); isolate_->factory()->this_symbol(),
var->set_rewrite(new Slot(var, Slot::PARAMETER, -1)); Variable::VAR,
false,
Variable::THIS);
var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1));
receiver_ = var; receiver_ = var;
} }
@ -305,8 +312,11 @@ void Scope::Initialize(bool inside_with) {
// Declare 'arguments' variable which exists in all functions. // Declare 'arguments' variable which exists in all functions.
// Note that it might never be accessed, in which case it won't be // Note that it might never be accessed, in which case it won't be
// allocated during variable allocation. // allocated during variable allocation.
variables_.Declare(this, FACTORY->arguments_symbol(), Variable::VAR, variables_.Declare(this,
true, Variable::ARGUMENTS); isolate_->factory()->arguments_symbol(),
Variable::VAR,
true,
Variable::ARGUMENTS);
} }
} }
@ -320,7 +330,7 @@ Variable* Scope::LocalLookup(Handle<String> name) {
// //
// We should never lookup 'arguments' in this scope as it is implicitly // We should never lookup 'arguments' in this scope as it is implicitly
// present in every scope. // present in every scope.
ASSERT(*name != *FACTORY->arguments_symbol()); ASSERT(*name != *isolate_->factory()->arguments_symbol());
// There should be no local slot with the given name. // There should be no local slot with the given name.
ASSERT(scope_info_->StackSlotIndex(*name) < 0); ASSERT(scope_info_->StackSlotIndex(*name) < 0);
@ -340,7 +350,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(new Slot(var, Slot::CONTEXT, index)); var->set_rewrite(NewSlot(var, Slot::CONTEXT, index));
return var; return var;
} }
@ -397,7 +407,8 @@ VariableProxy* Scope::NewUnresolved(Handle<String> name,
// the same name because they may be removed selectively via // the same name because they may be removed selectively via
// RemoveUnresolved(). // RemoveUnresolved().
ASSERT(!already_resolved()); ASSERT(!already_resolved());
VariableProxy* proxy = new VariableProxy(name, false, inside_with, position); VariableProxy* proxy = new(isolate_->zone()) VariableProxy(
isolate_, name, false, inside_with, position);
unresolved_.Add(proxy); unresolved_.Add(proxy);
return proxy; return proxy;
} }
@ -697,7 +708,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(new Slot(var, Slot::LOOKUP, -1)); var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1));
} }
return var; return var;
} }
@ -943,26 +954,28 @@ bool Scope::MustAllocateInContext(Variable* var) {
bool Scope::HasArgumentsParameter() { bool Scope::HasArgumentsParameter() {
for (int i = 0; i < params_.length(); i++) { for (int i = 0; i < params_.length(); i++) {
if (params_[i]->name().is_identical_to(FACTORY->arguments_symbol())) if (params_[i]->name().is_identical_to(
isolate_->factory()->arguments_symbol())) {
return true; return true;
}
} }
return false; return false;
} }
void Scope::AllocateStackSlot(Variable* var) { void Scope::AllocateStackSlot(Variable* var) {
var->set_rewrite(new Slot(var, Slot::LOCAL, num_stack_slots_++)); var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++));
} }
void Scope::AllocateHeapSlot(Variable* var) { void Scope::AllocateHeapSlot(Variable* var) {
var->set_rewrite(new Slot(var, Slot::CONTEXT, num_heap_slots_++)); var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++));
} }
void Scope::AllocateParameterLocals() { void Scope::AllocateParameterLocals() {
ASSERT(is_function_scope()); ASSERT(is_function_scope());
Variable* arguments = LocalLookup(FACTORY->arguments_symbol()); Variable* arguments = LocalLookup(isolate_->factory()->arguments_symbol());
ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
bool uses_nonstrict_arguments = false; bool uses_nonstrict_arguments = false;
@ -1009,7 +1022,7 @@ void Scope::AllocateParameterLocals() {
} else { } else {
ASSERT(var->rewrite() == NULL || var->IsParameter()); ASSERT(var->rewrite() == NULL || var->IsParameter());
if (var->rewrite() == NULL) { if (var->rewrite() == NULL) {
var->set_rewrite(new Slot(var, Slot::PARAMETER, i)); var->set_rewrite(NewSlot(var, Slot::PARAMETER, i));
} }
} }
} }
@ -1020,7 +1033,7 @@ 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->rewrite() == NULL ||
!var->IsVariable(FACTORY->result_symbol()) || !var->IsVariable(isolate_->factory()->result_symbol()) ||
var->AsSlot() == NULL || var->AsSlot() == NULL ||
var->AsSlot()->type() != Slot::LOCAL); var->AsSlot()->type() != Slot::LOCAL);
if (var->rewrite() == NULL && MustAllocate(var)) { if (var->rewrite() == NULL && MustAllocate(var)) {

6
deps/v8/src/scopes.h

@ -319,6 +319,8 @@ class Scope: public ZoneObject {
explicit Scope(Type type); explicit Scope(Type type);
Isolate* const isolate_;
// Scope tree. // Scope tree.
Scope* outer_scope_; // the immediately enclosing outer scope, or NULL Scope* outer_scope_; // the immediately enclosing outer scope, or NULL
ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes
@ -423,6 +425,10 @@ 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);

57
deps/v8/src/spaces.cc

@ -402,7 +402,9 @@ void MemoryAllocator::FreeRawMemory(void* mem,
size_t length, size_t length,
Executability executable) { Executability executable) {
#ifdef DEBUG #ifdef DEBUG
ZapBlock(reinterpret_cast<Address>(mem), length); // Do not try to zap the guard page.
size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0;
ZapBlock(reinterpret_cast<Address>(mem) + guard_size, length - guard_size);
#endif #endif
if (isolate_->code_range()->contains(static_cast<Address>(mem))) { if (isolate_->code_range()->contains(static_cast<Address>(mem))) {
isolate_->code_range()->FreeRawMemory(mem, length); isolate_->code_range()->FreeRawMemory(mem, length);
@ -504,14 +506,28 @@ Page* MemoryAllocator::AllocatePages(int requested_pages,
LOG(isolate_, NewEvent("PagedChunk", chunk, chunk_size)); LOG(isolate_, NewEvent("PagedChunk", chunk, chunk_size));
*allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size); *allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size);
// We may 'lose' a page due to alignment. // We may 'lose' a page due to alignment.
ASSERT(*allocated_pages >= kPagesPerChunk - 1); ASSERT(*allocated_pages >= kPagesPerChunk - 1);
if (*allocated_pages == 0) {
FreeRawMemory(chunk, chunk_size, owner->executable()); size_t guard_size = (owner->executable() == EXECUTABLE) ? Page::kPageSize : 0;
// Check that we got at least one page that we can use.
if (*allocated_pages <= ((guard_size != 0) ? 1 : 0)) {
FreeRawMemory(chunk,
chunk_size,
owner->executable());
LOG(isolate_, DeleteEvent("PagedChunk", chunk)); LOG(isolate_, DeleteEvent("PagedChunk", chunk));
return Page::FromAddress(NULL); return Page::FromAddress(NULL);
} }
if (guard_size != 0) {
OS::Guard(chunk, guard_size);
chunk_size -= guard_size;
chunk = static_cast<Address>(chunk) + guard_size;
--*allocated_pages;
}
int chunk_id = Pop(); int chunk_id = Pop();
chunks_[chunk_id].init(static_cast<Address>(chunk), chunk_size, owner); chunks_[chunk_id].init(static_cast<Address>(chunk), chunk_size, owner);
@ -681,7 +697,8 @@ void MemoryAllocator::DeleteChunk(int chunk_id) {
LOG(isolate_, DeleteEvent("PagedChunk", c.address())); LOG(isolate_, DeleteEvent("PagedChunk", c.address()));
ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner_identity()); ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner_identity());
size_t size = c.size(); size_t size = c.size();
FreeRawMemory(c.address(), size, c.executable()); size_t guard_size = (c.executable() == EXECUTABLE) ? Page::kPageSize : 0;
FreeRawMemory(c.address() - guard_size, size + guard_size, c.executable());
PerformAllocationCallback(space, kAllocationActionFree, size); PerformAllocationCallback(space, kAllocationActionFree, size);
} }
c.init(NULL, 0, NULL); c.init(NULL, 0, NULL);
@ -2672,9 +2689,10 @@ LargeObjectChunk* LargeObjectChunk::New(int size_in_bytes,
Executability executable) { Executability executable) {
size_t requested = ChunkSizeFor(size_in_bytes); size_t requested = ChunkSizeFor(size_in_bytes);
size_t size; size_t size;
size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0;
Isolate* isolate = Isolate::Current(); Isolate* isolate = Isolate::Current();
void* mem = isolate->memory_allocator()->AllocateRawMemory( void* mem = isolate->memory_allocator()->AllocateRawMemory(
requested, &size, executable); requested + guard_size, &size, executable);
if (mem == NULL) return NULL; if (mem == NULL) return NULL;
// The start of the chunk may be overlayed with a page so we have to // The start of the chunk may be overlayed with a page so we have to
@ -2682,13 +2700,19 @@ LargeObjectChunk* LargeObjectChunk::New(int size_in_bytes,
ASSERT((size & Page::kPageFlagMask) == 0); ASSERT((size & Page::kPageFlagMask) == 0);
LOG(isolate, NewEvent("LargeObjectChunk", mem, size)); LOG(isolate, NewEvent("LargeObjectChunk", mem, size));
if (size < requested) { if (size < requested + guard_size) {
isolate->memory_allocator()->FreeRawMemory( isolate->memory_allocator()->FreeRawMemory(
mem, size, executable); mem, size, executable);
LOG(isolate, DeleteEvent("LargeObjectChunk", mem)); LOG(isolate, DeleteEvent("LargeObjectChunk", mem));
return NULL; return NULL;
} }
if (guard_size != 0) {
OS::Guard(mem, guard_size);
size -= guard_size;
mem = static_cast<Address>(mem) + guard_size;
}
ObjectSpace space = (executable == EXECUTABLE) ObjectSpace space = (executable == EXECUTABLE)
? kObjectSpaceCodeSpace ? kObjectSpaceCodeSpace
: kObjectSpaceLoSpace; : kObjectSpaceLoSpace;
@ -2742,9 +2766,11 @@ void LargeObjectSpace::TearDown() {
ObjectSpace space = kObjectSpaceLoSpace; ObjectSpace space = kObjectSpaceLoSpace;
if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace;
size_t size = chunk->size(); size_t size = chunk->size();
heap()->isolate()->memory_allocator()->FreeRawMemory(chunk->address(), size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0;
size, heap()->isolate()->memory_allocator()->FreeRawMemory(
executable); chunk->address() - guard_size,
size + guard_size,
executable);
heap()->isolate()->memory_allocator()->PerformAllocationCallback( heap()->isolate()->memory_allocator()->PerformAllocationCallback(
space, kAllocationActionFree, size); space, kAllocationActionFree, size);
} }
@ -2941,10 +2967,15 @@ void LargeObjectSpace::FreeUnmarkedObjects() {
objects_size_ -= object->Size(); objects_size_ -= object->Size();
page_count_--; page_count_--;
ObjectSpace space = kObjectSpaceLoSpace; ObjectSpace space = kObjectSpaceLoSpace;
if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; size_t guard_size = 0;
heap()->isolate()->memory_allocator()->FreeRawMemory(chunk_address, if (executable == EXECUTABLE) {
chunk_size, space = kObjectSpaceCodeSpace;
executable); guard_size = Page::kPageSize;
}
heap()->isolate()->memory_allocator()->FreeRawMemory(
chunk_address - guard_size,
chunk_size + guard_size,
executable);
heap()->isolate()->memory_allocator()->PerformAllocationCallback( heap()->isolate()->memory_allocator()->PerformAllocationCallback(
space, kAllocationActionFree, size_); space, kAllocationActionFree, size_);
LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk_address)); LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk_address));

3
deps/v8/src/spaces.h

@ -647,13 +647,11 @@ class MemoryAllocator {
#ifdef V8_TARGET_ARCH_X64 #ifdef V8_TARGET_ARCH_X64
static const int kPagesPerChunk = 32; static const int kPagesPerChunk = 32;
// On 64 bit the chunk table consists of 4 levels of 4096-entry tables. // On 64 bit the chunk table consists of 4 levels of 4096-entry tables.
static const int kPagesPerChunkLog2 = 5;
static const int kChunkTableLevels = 4; static const int kChunkTableLevels = 4;
static const int kChunkTableBitsPerLevel = 12; static const int kChunkTableBitsPerLevel = 12;
#else #else
static const int kPagesPerChunk = 16; static const int kPagesPerChunk = 16;
// On 32 bit the chunk table consists of 2 levels of 256-entry tables. // On 32 bit the chunk table consists of 2 levels of 256-entry tables.
static const int kPagesPerChunkLog2 = 4;
static const int kChunkTableLevels = 2; static const int kChunkTableLevels = 2;
static const int kChunkTableBitsPerLevel = 8; static const int kChunkTableBitsPerLevel = 8;
#endif #endif
@ -662,7 +660,6 @@ class MemoryAllocator {
MemoryAllocator(); MemoryAllocator();
static const int kChunkSize = kPagesPerChunk * Page::kPageSize; static const int kChunkSize = kPagesPerChunk * Page::kPageSize;
static const int kChunkSizeLog2 = kPagesPerChunkLog2 + kPageSizeBits;
// Maximum space size in bytes. // Maximum space size in bytes.
intptr_t capacity_; intptr_t capacity_;

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

@ -662,6 +662,8 @@ class KeyedLoadStubCompiler: public StubCompiler {
static void GenerateLoadFastElement(MacroAssembler* masm); static void GenerateLoadFastElement(MacroAssembler* masm);
static void GenerateLoadFastDoubleElement(MacroAssembler* masm);
static void GenerateLoadDictionaryElement(MacroAssembler* masm); static void GenerateLoadDictionaryElement(MacroAssembler* masm);
private: private:
@ -717,6 +719,9 @@ class KeyedStoreStubCompiler: public StubCompiler {
static void GenerateStoreFastElement(MacroAssembler* masm, static void GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array); bool is_js_array);
static void GenerateStoreFastDoubleElement(MacroAssembler* masm,
bool is_js_array);
static void GenerateStoreExternalArray(MacroAssembler* masm, static void GenerateStoreExternalArray(MacroAssembler* masm,
JSObject::ElementsKind elements_kind); JSObject::ElementsKind elements_kind);

18
deps/v8/src/v8.cc

@ -50,6 +50,9 @@ bool V8::has_been_disposed_ = false;
bool V8::has_fatal_error_ = false; bool V8::has_fatal_error_ = false;
bool V8::use_crankshaft_ = true; bool V8::use_crankshaft_ = true;
static Mutex* entropy_mutex = OS::CreateMutex();
static EntropySource entropy_source;
bool V8::Initialize(Deserializer* des) { bool V8::Initialize(Deserializer* des) {
InitializeOncePerProcess(); InitializeOncePerProcess();
@ -102,8 +105,14 @@ void V8::TearDown() {
static void seed_random(uint32_t* state) { static void seed_random(uint32_t* state) {
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
state[i] = FLAG_random_seed; if (FLAG_random_seed != 0) {
while (state[i] == 0) { state[i] = FLAG_random_seed;
} else if (entropy_source != NULL) {
uint32_t val;
ScopedLock lock(entropy_mutex);
entropy_source(reinterpret_cast<unsigned char*>(&val), sizeof(uint32_t));
state[i] = val;
} else {
state[i] = random(); state[i] = random();
} }
} }
@ -124,6 +133,11 @@ static uint32_t random_base(uint32_t* state) {
} }
void V8::SetEntropySource(EntropySource source) {
entropy_source = source;
}
// Used by JavaScript APIs // Used by JavaScript APIs
uint32_t V8::Random(Isolate* isolate) { uint32_t V8::Random(Isolate* isolate) {
ASSERT(isolate == Isolate::Current()); ASSERT(isolate == Isolate::Current());

3
deps/v8/src/v8.h

@ -91,6 +91,9 @@ class V8 : public AllStatic {
static void FatalProcessOutOfMemory(const char* location, static void FatalProcessOutOfMemory(const char* location,
bool take_snapshot = false); bool take_snapshot = false);
// Allows an entropy source to be provided for use in random number
// generation.
static void SetEntropySource(EntropySource source);
// Random number generation support. Not cryptographically safe. // Random number generation support. Not cryptographically safe.
static uint32_t Random(Isolate* isolate); static uint32_t Random(Isolate* isolate);
// We use random numbers internally in memory allocation and in the // We use random numbers internally in memory allocation and in the

10
deps/v8/src/v8globals.h

@ -506,6 +506,16 @@ enum CallKind {
CALL_AS_FUNCTION CALL_AS_FUNCTION
}; };
static const uint32_t kHoleNanUpper32 = 0x7FFFFFFF;
static const uint32_t kHoleNanLower32 = 0xFFFFFFFF;
static const uint32_t kNaNOrInfinityLowerBoundUpper32 = 0x7FF00000;
const uint64_t kHoleNanInt64 =
(static_cast<uint64_t>(kHoleNanUpper32) << 32) | kHoleNanLower32;
const uint64_t kLastNonNaNInt64 =
(static_cast<uint64_t>(kNaNOrInfinityLowerBoundUpper32) << 32);
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_V8GLOBALS_H_ #endif // V8_V8GLOBALS_H_

43
deps/v8/src/v8natives.js

@ -675,7 +675,8 @@ function DefineProxyProperty(obj, p, attributes, should_throw) {
var result = %_CallFunction(handler, p, attributes, defineProperty); var result = %_CallFunction(handler, p, attributes, defineProperty);
if (!ToBoolean(result)) { if (!ToBoolean(result)) {
if (should_throw) { if (should_throw) {
throw MakeTypeError("handler_failed", [handler, "defineProperty"]); throw MakeTypeError("handler_returned_false",
[handler, "defineProperty"]);
} else { } else {
return false; return false;
} }
@ -1032,11 +1033,30 @@ function ObjectDefineProperties(obj, properties) {
} }
// Harmony proxies.
function ProxyFix(obj) {
var handler = %GetHandler(obj);
var fix = handler.fix;
if (IS_UNDEFINED(fix)) {
throw MakeTypeError("handler_trap_missing", [handler, "fix"]);
}
var props = %_CallFunction(handler, fix);
if (IS_UNDEFINED(props)) {
throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
}
%Fix(obj);
ObjectDefineProperties(obj, props);
}
// ES5 section 15.2.3.8. // ES5 section 15.2.3.8.
function ObjectSeal(obj) { function ObjectSeal(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["seal"]); throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
} }
if (%IsJSProxy(obj)) {
ProxyFix(obj);
}
var names = ObjectGetOwnPropertyNames(obj); var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) { for (var i = 0; i < names.length; i++) {
var name = names[i]; var name = names[i];
@ -1046,7 +1066,8 @@ function ObjectSeal(obj) {
DefineOwnProperty(obj, name, desc, true); DefineOwnProperty(obj, name, desc, true);
} }
} }
return ObjectPreventExtension(obj); %PreventExtensions(obj);
return obj;
} }
@ -1055,6 +1076,9 @@ function ObjectFreeze(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]); throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
} }
if (%IsJSProxy(obj)) {
ProxyFix(obj);
}
var names = ObjectGetOwnPropertyNames(obj); var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) { for (var i = 0; i < names.length; i++) {
var name = names[i]; var name = names[i];
@ -1065,7 +1089,8 @@ function ObjectFreeze(obj) {
DefineOwnProperty(obj, name, desc, true); DefineOwnProperty(obj, name, desc, true);
} }
} }
return ObjectPreventExtension(obj); %PreventExtensions(obj);
return obj;
} }
@ -1074,6 +1099,9 @@ function ObjectPreventExtension(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]); throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
} }
if (%IsJSProxy(obj)) {
ProxyFix(obj);
}
%PreventExtensions(obj); %PreventExtensions(obj);
return obj; return obj;
} }
@ -1084,6 +1112,9 @@ function ObjectIsSealed(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]); throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
} }
if (%IsJSProxy(obj)) {
return false;
}
var names = ObjectGetOwnPropertyNames(obj); var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) { for (var i = 0; i < names.length; i++) {
var name = names[i]; var name = names[i];
@ -1102,6 +1133,9 @@ function ObjectIsFrozen(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]); throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
} }
if (%IsJSProxy(obj)) {
return false;
}
var names = ObjectGetOwnPropertyNames(obj); var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) { for (var i = 0; i < names.length; i++) {
var name = names[i]; var name = names[i];
@ -1121,6 +1155,9 @@ function ObjectIsExtensible(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]); throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
} }
if (%IsJSProxy(obj)) {
return true;
}
return %IsExtensible(obj); return %IsExtensible(obj);
} }

4
deps/v8/src/version.cc

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

2
deps/v8/src/x64/assembler-x64.h

@ -125,7 +125,7 @@ struct Register {
return names[index]; return names[index];
} }
static Register toRegister(int code) { static Register from_code(int code) {
Register r = { code }; Register r = { code };
return r; return r;
} }

2
deps/v8/src/x64/code-stubs-x64.cc

@ -2529,6 +2529,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
#else #else
// Already there in AMD64 calling convention. // Already there in AMD64 calling convention.
ASSERT(arg1.is(rdi)); ASSERT(arg1.is(rdi));
USE(arg1);
#endif #endif
// Locate the code entry and call it. // Locate the code entry and call it.
@ -3198,6 +3199,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor = Handle<Code> adaptor =
Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline(); Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline();
__ SetCallKind(rcx, CALL_AS_METHOD);
__ Jump(adaptor, RelocInfo::CODE_TARGET); __ Jump(adaptor, RelocInfo::CODE_TARGET);
} }

14
deps/v8/src/x64/deoptimizer-x64.cc

@ -128,7 +128,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
Address instruction_start = function->code()->instruction_start(); Address instruction_start = function->code()->instruction_start();
Address jump_table_address = Address jump_table_address =
instruction_start + function->code()->safepoint_table_offset(); instruction_start + function->code()->safepoint_table_offset();
#ifdef DEBUG
Address previous_pc = instruction_start; Address previous_pc = instruction_start;
#endif
SafepointTableDeoptimiztionEntryIterator deoptimizations(function->code()); SafepointTableDeoptimiztionEntryIterator deoptimizations(function->code());
Address entry_pc = NULL; Address entry_pc = NULL;
@ -157,12 +159,16 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
CodePatcher patcher(call_address, Assembler::kCallInstructionLength); CodePatcher patcher(call_address, Assembler::kCallInstructionLength);
patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY), patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY),
RelocInfo::NONE); RelocInfo::NONE);
#ifdef DEBUG
previous_pc = call_end_address; previous_pc = call_end_address;
#endif
} else { } else {
// Not room enough for a long Call instruction. Write a short call // Not room enough for a long Call instruction. Write a short call
// instruction to a long jump placed elsewhere in the code. // instruction to a long jump placed elsewhere in the code.
#ifdef DEBUG
Address short_call_end_address = Address short_call_end_address =
call_address + MacroAssembler::kShortCallInstructionLength; call_address + MacroAssembler::kShortCallInstructionLength;
#endif
ASSERT(next_pc >= short_call_end_address); ASSERT(next_pc >= short_call_end_address);
// Write jump in jump-table. // Write jump in jump-table.
@ -177,7 +183,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
CodePatcher call_patcher(call_address, CodePatcher call_patcher(call_address,
MacroAssembler::kShortCallInstructionLength); MacroAssembler::kShortCallInstructionLength);
call_patcher.masm()->call(jump_table_address); call_patcher.masm()->call(jump_table_address);
#ifdef DEBUG
previous_pc = short_call_end_address; previous_pc = short_call_end_address;
#endif
} }
// Continue with next deoptimization entry. // Continue with next deoptimization entry.
@ -643,7 +651,7 @@ void Deoptimizer::EntryGenerator::Generate() {
// We push all registers onto the stack, even though we do not need // We push all registers onto the stack, even though we do not need
// to restore all later. // to restore all later.
for (int i = 0; i < kNumberOfRegisters; i++) { for (int i = 0; i < kNumberOfRegisters; i++) {
Register r = Register::toRegister(i); Register r = Register::from_code(i);
__ push(r); __ push(r);
} }
@ -801,12 +809,12 @@ void Deoptimizer::EntryGenerator::Generate() {
// Restore the registers from the stack. // Restore the registers from the stack.
for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) { for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) {
Register r = Register::toRegister(i); Register r = Register::from_code(i);
// Do not restore rsp, simply pop the value into the next register // Do not restore rsp, simply pop the value into the next register
// and overwrite this afterwards. // and overwrite this afterwards.
if (r.is(rsp)) { if (r.is(rsp)) {
ASSERT(i > 0); ASSERT(i > 0);
r = Register::toRegister(i - 1); r = Register::from_code(i - 1);
} }
__ pop(r); __ pop(r);
} }

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

@ -4060,10 +4060,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
default: { default: {
VisitForAccumulatorValue(expr->right()); VisitForAccumulatorValue(expr->right());
Condition cc = no_condition; Condition cc = no_condition;
bool strict = false;
switch (op) { switch (op) {
case Token::EQ_STRICT: case Token::EQ_STRICT:
strict = true;
// Fall through. // Fall through.
case Token::EQ: case Token::EQ:
cc = equal; cc = equal;

66
deps/v8/src/x64/lithium-codegen-x64.cc

@ -1883,7 +1883,6 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
__ push(ToRegister(instr->InputAt(0))); __ push(ToRegister(instr->InputAt(0)));
__ Push(instr->function()); __ Push(instr->function());
Register temp = ToRegister(instr->TempAt(0));
static const int kAdditionalDelta = 10; static const int kAdditionalDelta = 10;
int delta = int delta =
masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
@ -2245,10 +2244,35 @@ void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
} }
Operand LCodeGen::BuildExternalArrayOperand( void LCodeGen::DoLoadKeyedFastDoubleElement(
LLoadKeyedFastDoubleElement* instr) {
Register elements = ToRegister(instr->elements());
XMMRegister result(ToDoubleRegister(instr->result()));
if (instr->hydrogen()->RequiresHoleCheck()) {
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
sizeof(kHoleNanLower32);
Operand hole_check_operand = BuildFastArrayOperand(
instr->elements(),
instr->key(),
JSObject::FAST_DOUBLE_ELEMENTS,
offset);
__ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
DeoptimizeIf(equal, instr->environment());
}
Operand double_load_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movsd(result, double_load_operand);
}
Operand LCodeGen::BuildFastArrayOperand(
LOperand* external_pointer, LOperand* external_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind) { JSObject::ElementsKind elements_kind,
uint32_t offset) {
Register external_pointer_reg = ToRegister(external_pointer); Register external_pointer_reg = ToRegister(external_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind); int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) { if (key->IsConstantOperand()) {
@ -2256,10 +2280,12 @@ Operand LCodeGen::BuildExternalArrayOperand(
if (constant_value & 0xF0000000) { if (constant_value & 0xF0000000) {
Abort("array index constant value too big"); Abort("array index constant value too big");
} }
return Operand(external_pointer_reg, constant_value * (1 << shift_size)); return Operand(external_pointer_reg,
constant_value * (1 << shift_size) + offset);
} else { } else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0); return Operand(external_pointer_reg, ToRegister(key),
scale_factor, offset);
} }
} }
@ -2267,8 +2293,8 @@ Operand LCodeGen::BuildExternalArrayOperand(
void LCodeGen::DoLoadKeyedSpecializedArrayElement( void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) { LLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind(); JSObject::ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildExternalArrayOperand(instr->external_pointer(), Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind)); instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result())); XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand); __ movss(result, operand);
@ -2994,8 +3020,8 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
void LCodeGen::DoStoreKeyedSpecializedArrayElement( void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) { LStoreKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind(); JSObject::ElementsKind elements_kind = instr->elements_kind();
Operand operand(BuildExternalArrayOperand(instr->external_pointer(), Operand operand(BuildFastArrayOperand(instr->external_pointer(),
instr->key(), elements_kind)); instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value())); XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value); __ cvtsd2ss(value, value);
@ -3072,6 +3098,28 @@ void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
} }
void LCodeGen::DoStoreKeyedFastDoubleElement(
LStoreKeyedFastDoubleElement* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
Register elements = ToRegister(instr->elements());
Label have_value;
__ ucomisd(value, value);
__ j(parity_odd, &have_value); // NaN.
ExternalReference canonical_nan_reference =
ExternalReference::address_of_canonical_non_hole_nan();
__ Set(kScratchRegister, BitCast<uint64_t>(
FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
__ movq(value, kScratchRegister);
__ bind(&have_value);
Operand double_store_operand = BuildFastArrayOperand(
instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
FixedDoubleArray::kHeaderSize - kHeapObjectTag);
__ movsd(double_store_operand, value);
}
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(rdx)); ASSERT(ToRegister(instr->object()).is(rdx));
ASSERT(ToRegister(instr->key()).is(rcx)); ASSERT(ToRegister(instr->key()).is(rcx));

5
deps/v8/src/x64/lithium-codegen-x64.h

@ -215,10 +215,11 @@ class LCodeGen BASE_EMBEDDED {
Register ToRegister(int index) const; Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const; XMMRegister ToDoubleRegister(int index) const;
Operand BuildExternalArrayOperand( Operand BuildFastArrayOperand(
LOperand* external_pointer, LOperand* external_pointer,
LOperand* key, LOperand* key,
JSObject::ElementsKind elements_kind); JSObject::ElementsKind elements_kind,
uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation. // Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr); void EmitIntegerMathAbs(LUnaryMathOperation* instr);

35
deps/v8/src/x64/lithium-x64.cc

@ -428,6 +428,15 @@ void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
} }
void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
elements()->PrintTo(stream);
stream->Add("[");
key()->PrintTo(stream);
stream->Add("] <- ");
value()->PrintTo(stream);
}
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) { void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream); object()->PrintTo(stream);
stream->Add("["); stream->Add("[");
@ -1822,6 +1831,18 @@ LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
} }
LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
HLoadKeyedFastDoubleElement* instr) {
ASSERT(instr->representation().IsDouble());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
LLoadKeyedFastDoubleElement* result =
new LLoadKeyedFastDoubleElement(elements, key);
return AssignEnvironment(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) { HLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind(); JSObject::ElementsKind elements_kind = instr->elements_kind();
@ -1874,6 +1895,20 @@ LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
} }
LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
HStoreKeyedFastDoubleElement* instr) {
ASSERT(instr->value()->representation().IsDouble());
ASSERT(instr->elements()->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32());
LOperand* elements = UseRegisterAtStart(instr->elements());
LOperand* val = UseTempRegister(instr->value());
LOperand* key = UseRegisterOrConstantAtStart(instr->key());
return new LStoreKeyedFastDoubleElement(elements, key, val);
}
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) { HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation()); Representation representation(instr->value()->representation());

40
deps/v8/src/x64/lithium-x64.h

@ -121,6 +121,7 @@ class LCodeGen;
V(LoadFunctionPrototype) \ V(LoadFunctionPrototype) \
V(LoadGlobalCell) \ V(LoadGlobalCell) \
V(LoadGlobalGeneric) \ V(LoadGlobalGeneric) \
V(LoadKeyedFastDoubleElement) \
V(LoadKeyedFastElement) \ V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \ V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \ V(LoadKeyedSpecializedArrayElement) \
@ -147,6 +148,7 @@ class LCodeGen;
V(StoreContextSlot) \ V(StoreContextSlot) \
V(StoreGlobalCell) \ V(StoreGlobalCell) \
V(StoreGlobalGeneric) \ V(StoreGlobalGeneric) \
V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \ V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \ V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \ V(StoreKeyedSpecializedArrayElement) \
@ -1134,6 +1136,22 @@ class LLoadKeyedFastElement: public LTemplateInstruction<1, 2, 0> {
}; };
class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
inputs_[0] = elements;
inputs_[1] = key;
}
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
"load-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
};
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> { class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public: public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer, LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
@ -1585,6 +1603,28 @@ class LStoreKeyedFastElement: public LTemplateInstruction<0, 3, 0> {
}; };
class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyedFastDoubleElement(LOperand* elements,
LOperand* key,
LOperand* val) {
inputs_[0] = elements;
inputs_[1] = key;
inputs_[2] = val;
}
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
"store-keyed-fast-double-element")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
virtual void PrintDataTo(StringStream* stream);
LOperand* elements() { return inputs_[0]; }
LOperand* key() { return inputs_[1]; }
LOperand* value() { return inputs_[2]; }
};
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> { class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public: public:
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,

3
deps/v8/src/x64/macro-assembler-x64.cc

@ -384,6 +384,9 @@ void MacroAssembler::AssertFastElements(Register elements) {
CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
Heap::kFixedArrayMapRootIndex); Heap::kFixedArrayMapRootIndex);
j(equal, &ok, Label::kNear); j(equal, &ok, Label::kNear);
CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
Heap::kFixedDoubleArrayMapRootIndex);
j(equal, &ok, Label::kNear);
CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
Heap::kFixedCOWArrayMapRootIndex); Heap::kFixedCOWArrayMapRootIndex);
j(equal, &ok, Label::kNear); j(equal, &ok, Label::kNear);

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

@ -661,7 +661,6 @@ bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type,
} }
__ movq(rbx, ExternalReference::re_word_character_map()); __ movq(rbx, ExternalReference::re_word_character_map());
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char. ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
ExternalReference word_map = ExternalReference::re_word_character_map();
__ testb(Operand(rbx, current_character(), times_1, 0), __ testb(Operand(rbx, current_character(), times_1, 0),
current_character()); current_character());
BranchOrBacktrack(zero, on_no_match); BranchOrBacktrack(zero, on_no_match);
@ -676,7 +675,6 @@ bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type,
} }
__ movq(rbx, ExternalReference::re_word_character_map()); __ movq(rbx, ExternalReference::re_word_character_map());
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char. ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
ExternalReference word_map = ExternalReference::re_word_character_map();
__ testb(Operand(rbx, current_character(), times_1, 0), __ testb(Operand(rbx, current_character(), times_1, 0),
current_character()); current_character());
BranchOrBacktrack(not_zero, on_no_match); BranchOrBacktrack(not_zero, on_no_match);

140
deps/v8/src/x64/stub-cache-x64.cc

@ -1089,9 +1089,8 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
__ JumpIfSmi(receiver, miss); __ JumpIfSmi(receiver, miss);
// Check that the maps haven't changed. // Check that the maps haven't changed.
Register reg = CheckPrototypes(object, receiver, holder,
CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, name, miss);
scratch1, scratch2, scratch3, name, miss);
// Return the constant value. // Return the constant value.
__ Move(rax, Handle<Object>(value)); __ Move(rax, Handle<Object>(value));
@ -3584,6 +3583,57 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
} }
void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
Label miss_force_generic, slow_allocate_heapnumber;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ JumpIfNotSmi(rax, &miss_force_generic);
// Get the elements array.
__ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
__ AssertFastElements(rcx);
// Check that the key is within bounds.
__ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset));
__ j(above_equal, &miss_force_generic);
// Check for the hole
__ SmiToInteger32(kScratchRegister, rax);
uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
__ cmpl(FieldOperand(rcx, kScratchRegister, times_8, offset),
Immediate(kHoleNanUpper32));
__ j(equal, &miss_force_generic);
// Always allocate a heap number for the result.
__ movsd(xmm0, FieldOperand(rcx, kScratchRegister, times_8,
FixedDoubleArray::kHeaderSize));
__ AllocateHeapNumber(rcx, rbx, &slow_allocate_heapnumber);
// Set the value.
__ movq(rax, rcx);
__ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
__ ret(0);
__ bind(&slow_allocate_heapnumber);
Handle<Code> slow_ic =
masm->isolate()->builtins()->KeyedLoadIC_Slow();
__ jmp(slow_ic, RelocInfo::CODE_TARGET);
__ bind(&miss_force_generic);
Handle<Code> miss_ic =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
__ jmp(miss_ic, RelocInfo::CODE_TARGET);
}
void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array) { bool is_js_array) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
@ -3634,6 +3684,90 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm,
} }
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
MacroAssembler* masm,
bool is_js_array) {
// ----------- S t a t e -------------
// -- rax : value
// -- rcx : key
// -- rdx : receiver
// -- rsp[0] : return address
// -----------------------------------
Label miss_force_generic, smi_value, is_nan, maybe_nan;
Label have_double_value, not_nan;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
// Check that the key is a smi.
__ JumpIfNotSmi(rcx, &miss_force_generic);
// Get the elements array.
__ movq(rdi, FieldOperand(rdx, JSObject::kElementsOffset));
__ AssertFastElements(rdi);
// Check that the key is within bounds.
if (is_js_array) {
__ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
} else {
__ SmiCompare(rcx, FieldOperand(rdi, FixedDoubleArray::kLengthOffset));
}
__ j(above_equal, &miss_force_generic);
// Handle smi values specially
__ JumpIfSmi(rax, &smi_value, Label::kNear);
__ CheckMap(rax,
masm->isolate()->factory()->heap_number_map(),
&miss_force_generic,
DONT_DO_SMI_CHECK);
// Double value, canonicalize NaN.
uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
__ cmpl(FieldOperand(rax, offset),
Immediate(kNaNOrInfinityLowerBoundUpper32));
__ j(greater_equal, &maybe_nan, Label::kNear);
__ bind(&not_nan);
__ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
__ bind(&have_double_value);
__ SmiToInteger32(rcx, rcx);
__ movsd(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize),
xmm0);
__ ret(0);
__ bind(&maybe_nan);
// Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
// it's an Infinity, and the non-NaN code path applies.
__ j(greater, &is_nan, Label::kNear);
__ cmpl(FieldOperand(rax, HeapNumber::kValueOffset), Immediate(0));
__ j(zero, &not_nan);
__ bind(&is_nan);
// Convert all NaNs to the same canonical NaN value when they are stored in
// the double array.
__ Set(kScratchRegister, BitCast<uint64_t>(
FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
__ movq(xmm0, kScratchRegister);
__ jmp(&have_double_value, Label::kNear);
__ bind(&smi_value);
// Value is a smi. convert to a double and store.
__ SmiToInteger32(rax, rax);
__ push(rax);
__ fild_s(Operand(rsp, 0));
__ pop(rax);
__ SmiToInteger32(rcx, rcx);
__ fstp_d(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize));
__ ret(0);
// Handle store cache miss, replacing the ic with the generic stub.
__ bind(&miss_force_generic);
Handle<Code> ic_force_generic =
masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
__ jmp(ic_force_generic, RelocInfo::CODE_TARGET);
}
#undef __ #undef __
} } // namespace v8::internal } } // namespace v8::internal

2
deps/v8/src/zone.h

@ -74,6 +74,8 @@ class Zone {
inline void adjust_segment_bytes_allocated(int delta); inline void adjust_segment_bytes_allocated(int delta);
inline Isolate* isolate() { return isolate_; }
static unsigned allocation_size_; static unsigned allocation_size_;
private: private:

24
deps/v8/test/cctest/SConscript

@ -29,9 +29,23 @@ import sys
from os.path import join, dirname, abspath from os.path import join, dirname, abspath
root_dir = dirname(File('SConstruct').rfile().abspath) root_dir = dirname(File('SConstruct').rfile().abspath)
sys.path.append(join(root_dir, 'tools')) sys.path.append(join(root_dir, 'tools'))
import js2c
Import('context object_files tools') Import('context object_files tools')
# Needed for test-log. Paths are relative to the cctest dir.
JS_FILES_FOR_TESTS = [
'../../../tools/splaytree.js',
'../../../tools/codemap.js',
'../../../tools/csvparser.js',
'../../../tools/consarray.js',
'../../../tools/profile.js',
'../../../tools/profile_view.js',
'../../../tools/logreader.js',
'log-eq-of-logging-and-traversal.js',
]
SOURCES = { SOURCES = {
'all': [ 'all': [
'gay-fixed.cc', 'gay-fixed.cc',
@ -109,9 +123,19 @@ def Build():
env = Environment(tools=tools) env = Environment(tools=tools)
env.Replace(**context.flags['cctest']) env.Replace(**context.flags['cctest'])
context.ApplyEnvOverrides(env) context.ApplyEnvOverrides(env)
env['BUILDERS']['JS2C'] = Builder(action=js2c.JS2C)
# Combine the JavaScript library files into a single C++ file and
# compile it.
js_files = [s for s in JS_FILES_FOR_TESTS]
js_files_src = env.JS2C(
['js-files-for-cctest.cc'], js_files, **{'TYPE': 'TEST', 'COMPRESSION': 'off'})
js_files_obj = context.ConfigureObject(env, js_files_src, CPPPATH=['.'])
# There seems to be a glitch in the way scons decides where to put # There seems to be a glitch in the way scons decides where to put
# PDB files when compiling using MSVC so we specify it manually. # PDB files when compiling using MSVC so we specify it manually.
# This should not affect any other platforms. # This should not affect any other platforms.
object_files.append(js_files_obj)
return env.Program('cctest', ['cctest.cc', cctest_files, object_files], return env.Program('cctest', ['cctest.cc', cctest_files, object_files],
PDB='cctest.exe.pdb') PDB='cctest.exe.pdb')

41
deps/v8/test/cctest/cctest.gyp

@ -26,6 +26,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{ {
'variables': {
'generated_file': '<(SHARED_INTERMEDIATE_DIR)/resources.cc',
},
'includes': [ '../../build/v8-features.gypi' ], 'includes': [ '../../build/v8-features.gypi' ],
'targets': [ 'targets': [
{ {
@ -33,11 +36,13 @@
'type': 'executable', 'type': 'executable',
'dependencies': [ 'dependencies': [
'../../tools/gyp/v8.gyp:v8', '../../tools/gyp/v8.gyp:v8',
'resources',
], ],
'include_dirs': [ 'include_dirs': [
'../../src', '../../src',
], ],
'sources': [ 'sources': [
'<(generated_file)',
'cctest.cc', 'cctest.cc',
'gay-fixed.cc', 'gay-fixed.cc',
'gay-precision.cc', 'gay-precision.cc',
@ -131,5 +136,41 @@
}], }],
], ],
}, },
{
'target_name': 'resources',
'type': 'none',
'variables': {
'file_list': [
'../../tools/splaytree.js',
'../../tools/codemap.js',
'../../tools/csvparser.js',
'../../tools/consarray.js',
'../../tools/profile.js',
'../../tools/profile_view.js',
'../../tools/logreader.js',
'log-eq-of-logging-and-traversal.js',
],
},
'actions': [
{
'action_name': 'js2c',
'inputs': [
'../../tools/js2c.py',
'<@(file_list)',
],
'outputs': [
'<(generated_file)',
],
'action': [
'python',
'../../tools/js2c.py',
'<@(_outputs)',
'TEST', # type
'off', # compression
'<@(file_list)',
],
}
],
},
], ],
} }

22
deps/v8/test/cctest/log-eq-of-logging-and-traversal.js

@ -137,36 +137,38 @@ function RunTest() {
return entityA.size === entityB.size && entityNamesEqual(entityA, entityB); return entityA.size === entityB.size && entityNamesEqual(entityA, entityB);
} }
var i = 0, j = 0, k = logging_entries.length, l = traversal_entries.length; var l_pos = 0, t_pos = 0;
var l_len = logging_entries.length, t_len = traversal_entries.length;
var comparison = []; var comparison = [];
var equal = true; var equal = true;
// Do a merge-like comparison of entries. At the same address we expect to // Do a merge-like comparison of entries. At the same address we expect to
// find the same entries. We skip builtins during log parsing, but compiled // find the same entries. We skip builtins during log parsing, but compiled
// functions traversal may erroneously recognize them as functions, so we are // functions traversal may erroneously recognize them as functions, so we are
// expecting more functions in traversal vs. logging. // expecting more functions in traversal vs. logging.
while (i < k && j < l) { while (l_pos < l_len && t_pos < t_len) {
var entryA = logging_entries[i], entryB = traversal_entries[j]; var entryA = logging_entries[l_pos];
var entryB = traversal_entries[t_pos];
var cmp = addressComparator(entryA, entryB); var cmp = addressComparator(entryA, entryB);
var entityA = entryA[1], entityB = entryB[1]; var entityA = entryA[1], entityB = entryB[1];
var address = entryA[0]; var address = entryA[0];
if (cmp < 0) { if (cmp < 0) {
++i; ++l_pos;
entityB = null; entityB = null;
} else if (cmp > 0) { } else if (cmp > 0) {
++j; ++t_pos;
entityA = null; entityA = null;
address = entryB[0]; address = entryB[0];
} else { } else {
++i; ++l_pos;
++j; ++t_pos;
} }
var entities_equal = entitiesEqual(entityA, entityB); var entities_equal = entitiesEqual(entityA, entityB);
if (!entities_equal) equal = false; if (!entities_equal) equal = false;
comparison.push([entities_equal, address, entityA, entityB]); comparison.push([entities_equal, address, entityA, entityB]);
} }
if (i < k) equal = false; if (l_pos < l_len) equal = false;
while (i < k) { while (l_pos < l_len) {
var entryA = logging_entries[i++]; var entryA = logging_entries[l_pos++];
comparison.push([false, entryA[0], entryA[1], null]); comparison.push([false, entryA[0], entryA[1], null]);
} }
return [equal, comparison]; return [equal, comparison];

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

@ -1026,6 +1026,90 @@ THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
} }
THREADED_TEST(IsNativeError) {
v8::HandleScope scope;
LocalContext env;
v8::Handle<Value> syntax_error = CompileRun(
"var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
CHECK(syntax_error->IsNativeError());
v8::Handle<Value> not_error = CompileRun("{a:42}");
CHECK(!not_error->IsNativeError());
v8::Handle<Value> not_object = CompileRun("42");
CHECK(!not_object->IsNativeError());
}
THREADED_TEST(StringObject) {
v8::HandleScope scope;
LocalContext env;
v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
CHECK(boxed_string->IsStringObject());
v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
CHECK(!unboxed_string->IsStringObject());
v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
CHECK(!boxed_not_string->IsStringObject());
v8::Handle<Value> not_object = CompileRun("0");
CHECK(!not_object->IsStringObject());
v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
CHECK(!as_boxed.IsEmpty());
Local<v8::String> the_string = as_boxed->StringValue();
CHECK(!the_string.IsEmpty());
ExpectObject("\"test\"", the_string);
v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
CHECK(new_boxed_string->IsStringObject());
as_boxed = new_boxed_string.As<v8::StringObject>();
the_string = as_boxed->StringValue();
CHECK(!the_string.IsEmpty());
ExpectObject("\"test\"", the_string);
}
THREADED_TEST(NumberObject) {
v8::HandleScope scope;
LocalContext env;
v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
CHECK(boxed_number->IsNumberObject());
v8::Handle<Value> unboxed_number = CompileRun("42");
CHECK(!unboxed_number->IsNumberObject());
v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
CHECK(!boxed_not_number->IsNumberObject());
v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
CHECK(!as_boxed.IsEmpty());
double the_number = as_boxed->NumberValue();
CHECK_EQ(42.0, the_number);
v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
CHECK(new_boxed_number->IsNumberObject());
as_boxed = new_boxed_number.As<v8::NumberObject>();
the_number = as_boxed->NumberValue();
CHECK_EQ(43.0, the_number);
}
THREADED_TEST(BooleanObject) {
v8::HandleScope scope;
LocalContext env;
v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
CHECK(boxed_boolean->IsBooleanObject());
v8::Handle<Value> unboxed_boolean = CompileRun("true");
CHECK(!unboxed_boolean->IsBooleanObject());
v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
CHECK(!boxed_not_boolean->IsBooleanObject());
v8::Handle<v8::BooleanObject> as_boxed =
boxed_boolean.As<v8::BooleanObject>();
CHECK(!as_boxed.IsEmpty());
bool the_boolean = as_boxed->BooleanValue();
CHECK_EQ(true, the_boolean);
v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
CHECK(boxed_true->IsBooleanObject());
CHECK(boxed_false->IsBooleanObject());
as_boxed = boxed_true.As<v8::BooleanObject>();
CHECK_EQ(true, as_boxed->BooleanValue());
as_boxed = boxed_false.As<v8::BooleanObject>();
CHECK_EQ(false, as_boxed->BooleanValue());
}
THREADED_TEST(Number) { THREADED_TEST(Number) {
v8::HandleScope scope; v8::HandleScope scope;
LocalContext env; LocalContext env;
@ -2048,10 +2132,15 @@ THREADED_TEST(GetSetProperty) {
THREADED_TEST(PropertyAttributes) { THREADED_TEST(PropertyAttributes) {
v8::HandleScope scope; v8::HandleScope scope;
LocalContext context; LocalContext context;
// none
Local<String> prop = v8_str("none");
context->Global()->Set(prop, v8_num(7));
CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
// read-only // read-only
Local<String> prop = v8_str("read_only"); prop = v8_str("read_only");
context->Global()->Set(prop, v8_num(7), v8::ReadOnly); context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
Script::Compile(v8_str("read_only = 9"))->Run(); Script::Compile(v8_str("read_only = 9"))->Run();
CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
context->Global()->Set(prop, v8_num(10)); context->Global()->Set(prop, v8_num(10));
@ -2062,6 +2151,25 @@ THREADED_TEST(PropertyAttributes) {
CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Script::Compile(v8_str("delete dont_delete"))->Run(); Script::Compile(v8_str("delete dont_delete"))->Run();
CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
// dont-enum
prop = v8_str("dont_enum");
context->Global()->Set(prop, v8_num(28), v8::DontEnum);
CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
// absent
prop = v8_str("absent");
CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
Local<Value> fake_prop = v8_num(1);
CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
// exception
TryCatch try_catch;
Local<Value> exception =
CompileRun("({ toString: function() { throw 'exception';} })");
CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
CHECK(try_catch.HasCaught());
String::AsciiValue exception_value(try_catch.Exception());
CHECK_EQ("exception", *exception_value);
try_catch.Reset();
} }

2
deps/v8/test/cctest/test-ast.cc

@ -40,7 +40,7 @@ TEST(List) {
CHECK_EQ(0, list->length()); CHECK_EQ(0, list->length());
ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT); ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT);
AstNode* node = new EmptyStatement(); AstNode* node = new(ZONE) EmptyStatement();
list->Add(node); list->Add(node);
CHECK_EQ(1, list->length()); CHECK_EQ(1, list->length());
CHECK_EQ(node, list->at(0)); CHECK_EQ(node, list->at(0));

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

Loading…
Cancel
Save