diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-07-21 22:20:37 -0700 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-07-21 22:20:37 -0700 |
commit | f319e126218dcaafdb0ccf7e968ff839f8327bba (patch) | |
tree | 209546d94cdc6c19f69ef92e3ec057301369f416 /deps/v8 | |
parent | ef1be160d66b7da8bc2da857b1c33c6f680d86f1 (diff) | |
download | nodejs-f319e126218dcaafdb0ccf7e968ff839f8327bba.tar.gz nodejs-f319e126218dcaafdb0ccf7e968ff839f8327bba.tar.bz2 nodejs-f319e126218dcaafdb0ccf7e968ff839f8327bba.zip |
Upgrade V8 to 3.4.14
Diffstat (limited to 'deps/v8')
111 files changed, 4227 insertions, 920 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 7e7df0680..6901729b0 100644 --- a/deps/v8/ChangeLog +++ b/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 Added --prof profiling option to d8 shell. diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 5276ce2ca..8e16a7824 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -404,6 +404,7 @@ CCTEST_EXTRA_FLAGS = { }, 'os:linux': { 'LIBS': ['pthread'], + 'CCFLAGS': ['-Wno-unused-but-set-variable'], }, 'os:macos': { 'LIBS': ['pthread'], @@ -773,6 +774,13 @@ PREPARSER_FLAGS = { D8_FLAGS = { + 'all': { + 'library:shared': { + 'CPPDEFINES': ['V8_SHARED'], + 'LIBS': ['v8'], + 'LIBPATH': ['.'] + }, + }, 'gcc': { 'all': { 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], @@ -1370,7 +1378,11 @@ def BuildSpecific(env, mode, env_overrides, tools): d8_env = Environment(tools=tools) d8_env.Replace(**context.flags['d8']) 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) for sample in context.samples: diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 087241106..f4f81e4c7 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -80,9 +80,11 @@ namespace v8 { class Context; class String; +class StringObject; class Value; class Utils; class Number; +class NumberObject; class Object; class Array; class Int32; @@ -90,6 +92,7 @@ class Uint32; class External; class Primitive; class Boolean; +class BooleanObject; class Integer; class Function; class Date; @@ -929,6 +932,26 @@ class Value : public Data { 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. */ V8EXPORT bool IsRegExp() const; @@ -1435,6 +1458,13 @@ class Object : public Value { 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 // functions with generic ones that accept a Handle<Value> key. V8EXPORT bool Has(Handle<String> key); @@ -1745,6 +1775,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). */ class RegExp : public Object { @@ -2721,6 +2808,13 @@ class V8EXPORT StartupDataDecompressor { // NOLINT 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. */ @@ -2946,6 +3040,12 @@ class V8EXPORT V8 { 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 * V8 an indication of the amount of externally allocated memory * that is kept alive by JavaScript objects. V8 uses this to decide @@ -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) { #ifdef V8_ENABLE_CHECKS CheckCast(value); diff --git a/deps/v8/preparser/preparser-process.cc b/deps/v8/preparser/preparser-process.cc index d7c96f0c7..e67851cbd 100644 --- a/deps/v8/preparser/preparser-process.cc +++ b/deps/v8/preparser/preparser-process.cc @@ -208,7 +208,7 @@ void fail(v8::PreParserData* data, const char* message, ...) { fflush(stderr); } exit(EXIT_FAILURE); -}; +} bool IsFlag(const char* arg) { diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index 7c30beccd..f37e731f3 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -95,6 +95,13 @@ class SourceGroup { begin_offset_(0), end_offset_(0) { } +#if !(defined(USING_V8_SHARED) || defined(V8_SHARED)) + ~SourceGroup() { + delete next_semaphore_; + delete done_semaphore_; + } +#endif // USING_V8_SHARED + void Begin(char** argv, int offset) { argv_ = const_cast<const char**>(argv); begin_offset_ = offset; diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index 6b3059aea..b45a5677a 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -243,7 +243,14 @@ PREPARSER_SOURCES = { } -D8_FILES = { +D8_LIGHT_FILES = { + 'all': [ + 'd8.cc' + ] +} + + +D8_FULL_FILES = { 'all': [ 'd8.cc', 'd8-debug.cc' ], @@ -323,11 +330,15 @@ def ConfigureObjectFiles(): # Build the standard platform-independent source files. 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_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 # compile it. diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index dc1f90c0e..b0e977564 100644 --- a/deps/v8/src/api.cc +++ b/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 { if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsRegExp()")) return false; 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) { if (IsDeadCheck(i::Isolate::Current(), "v8::RegExp::Cast()")) return; 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() { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); 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() { i::Isolate* isolate = i::Isolate::Current(); 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) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::Date::New()"); diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index efa252dba..89df079f9 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/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; first_const_pool_use_ = -1; 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 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { - ASSERT(ast_id_for_reloc_info_ != kNoASTId); - RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_); - ast_id_for_reloc_info_ = kNoASTId; + RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId()); + ClearRecordedAstId(); reloc_info_writer.Write(&reloc_info_with_ast_id); } else { reloc_info_writer.Write(&rinfo); diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index fbf610a43..97d422650 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/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 // 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. // 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 // member variable is a way to pass the information from the call site to // the relocation info. - unsigned ast_id_for_reloc_info_; + unsigned recorded_ast_id_; bool emit_debug_code() const { return emit_debug_code_; } diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index ab7c6f247..eaad9f293 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/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(r2, Operand(0, RelocInfo::NONE)); __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); + __ SetCallKind(r5, CALL_AS_METHOD); __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), RelocInfo::CODE_TARGET); } diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index 22e7e4132..ea06064e5 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/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) { object()->PrintTo(stream); 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( HLoadKeyedSpecializedArrayElement* instr) { 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( HStoreKeyedSpecializedArrayElement* instr) { Representation representation(instr->value()->representation()); diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index ebeba8694..70c348de6 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -121,6 +121,7 @@ class LCodeGen; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ + V(LoadKeyedFastDoubleElement) \ V(LoadKeyedFastElement) \ V(LoadKeyedGeneric) \ V(LoadKeyedSpecializedArrayElement) \ @@ -147,6 +148,7 @@ class LCodeGen; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ + V(StoreKeyedFastDoubleElement) \ V(StoreKeyedFastElement) \ V(StoreKeyedGeneric) \ 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> { public: 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> { public: LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val) { diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index dc93aea34..e4a14af7e 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/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( LLoadKeyedSpecializedArrayElement* instr) { Register external_pointer = ToRegister(instr->external_pointer()); @@ -2453,9 +2495,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS || elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) { CpuFeatures::Scope scope(VFP3); - DwVfpRegister result(ToDoubleRegister(instr->result())); - Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size)) - : Operand(key, LSL, shift_size)); + DwVfpRegister result = ToDoubleRegister(instr->result()); + Operand operand = key_is_constant + ? Operand(constant_key * (1 << shift_size)) + : Operand(key, LSL, shift_size); __ add(scratch0(), external_pointer, operand); if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { __ vldr(result.low(), scratch0(), 0); @@ -2464,7 +2507,7 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement( __ vldr(result, scratch0(), 0); } } else { - Register result(ToRegister(instr->result())); + Register result = ToRegister(instr->result()); MemOperand mem_operand(key_is_constant ? MemOperand(external_pointer, constant_key * (1 << 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(¬_nan); + __ vstr(value, scratch, 0); +} + + void LCodeGen::DoStoreKeyedSpecializedArrayElement( LStoreKeyedSpecializedArrayElement* instr) { diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 320879a62..c34a57920 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -192,13 +192,13 @@ void MacroAssembler::Call(Handle<Code> code, bind(&start); ASSERT(RelocInfo::IsCodeTarget(rmode)); if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) { - ASSERT(ast_id_for_reloc_info_ == kNoASTId); - ast_id_for_reloc_info_ = ast_id; + SetRecordedAstId(ast_id); rmode = RelocInfo::CODE_TARGET_WITH_ID; } // 'code' is always generated ARM code, never THUMB code 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) { 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(); 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; } @@ -2548,6 +2549,9 @@ void MacroAssembler::AssertFastElements(Register elements) { LoadRoot(ip, Heap::kFixedArrayMapRootIndex); cmp(elements, ip); b(eq, &ok); + LoadRoot(ip, Heap::kFixedDoubleArrayMapRootIndex); + cmp(elements, ip); + b(eq, &ok); LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex); cmp(elements, ip); b(eq, &ok); diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 86e49716d..c2665f885 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/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, bool is_js_array) { // ----------- 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 __ } } // namespace v8::internal diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index 60cf3f0c5..e6c13d954 100644 --- a/deps/v8/src/array.js +++ b/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 // loop will not affect the looping. - var length = this.length; + var length = ToUint32(this.length); var result = []; var result_length = 0; 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 // loop will not affect the looping. - var length = this.length; + var length = ToUint32(this.length); var i = 0; find_initial: if (%_ArgumentsLength() < 2) { @@ -1268,7 +1268,7 @@ function ArrayReduceRight(callback, current) { if (!IS_FUNCTION(callback)) { throw MakeTypeError('called_non_callable', [callback]); } - var i = this.length - 1; + var i = ToUint32(this.length) - 1; find_initial: if (%_ArgumentsLength() < 2) { for (; i >= 0; i--) { diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 3c7fc1c63..fbd808958 100644 --- a/deps/v8/src/assembler.cc +++ b/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. // // 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::uint8_max_value = 255; 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 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*>( - 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))); } diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index bced11fec..2d14f0691 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -70,7 +70,8 @@ class DoubleConstant: public AllStatic { static const double zero; static const double uint8_max_value; 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_uint8_max_value(); 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_cos_double_function(Isolate* isolate); diff --git a/deps/v8/src/ast-inl.h b/deps/v8/src/ast-inl.h index c2bd61344..c750e6b03 100644 --- a/deps/v8/src/ast-inl.h +++ b/deps/v8/src/ast-inl.h @@ -37,68 +37,76 @@ namespace v8 { namespace internal { -SwitchStatement::SwitchStatement(ZoneStringList* labels) - : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), +SwitchStatement::SwitchStatement(Isolate* isolate, + ZoneStringList* labels) + : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS), tag_(NULL), cases_(NULL) { } -Block::Block(ZoneStringList* labels, int capacity, bool is_initializer_block) - : BreakableStatement(labels, TARGET_FOR_NAMED_ONLY), +Block::Block(Isolate* isolate, + ZoneStringList* labels, + int capacity, + bool is_initializer_block) + : BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY), statements_(capacity), is_initializer_block_(is_initializer_block) { } -BreakableStatement::BreakableStatement(ZoneStringList* labels, Type type) +BreakableStatement::BreakableStatement(Isolate* isolate, + ZoneStringList* labels, + Type type) : labels_(labels), type_(type), - entry_id_(GetNextId()), - exit_id_(GetNextId()) { + entry_id_(GetNextId(isolate)), + exit_id_(GetNextId(isolate)) { ASSERT(labels == NULL || labels->length() > 0); } -IterationStatement::IterationStatement(ZoneStringList* labels) - : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), +IterationStatement::IterationStatement(Isolate* isolate, ZoneStringList* labels) + : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS), body_(NULL), continue_target_(), - osr_entry_id_(GetNextId()) { + osr_entry_id_(GetNextId(isolate)) { } -DoWhileStatement::DoWhileStatement(ZoneStringList* labels) - : IterationStatement(labels), +DoWhileStatement::DoWhileStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), cond_(NULL), condition_position_(-1), - continue_id_(GetNextId()), - back_edge_id_(GetNextId()) { + continue_id_(GetNextId(isolate)), + back_edge_id_(GetNextId(isolate)) { } -WhileStatement::WhileStatement(ZoneStringList* labels) - : IterationStatement(labels), +WhileStatement::WhileStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), cond_(NULL), may_have_function_literal_(true), - body_id_(GetNextId()) { + body_id_(GetNextId(isolate)) { } -ForStatement::ForStatement(ZoneStringList* labels) - : IterationStatement(labels), +ForStatement::ForStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), init_(NULL), cond_(NULL), next_(NULL), may_have_function_literal_(true), loop_variable_(NULL), - continue_id_(GetNextId()), - body_id_(GetNextId()) { + continue_id_(GetNextId(isolate)), + body_id_(GetNextId(isolate)) { } -ForInStatement::ForInStatement(ZoneStringList* labels) - : IterationStatement(labels), each_(NULL), enumerable_(NULL), - assignment_id_(GetNextId()) { +ForInStatement::ForInStatement(Isolate* isolate, ZoneStringList* labels) + : IterationStatement(isolate, labels), + each_(NULL), + enumerable_(NULL), + assignment_id_(GetNextId(isolate)) { } diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 8b6cdcee9..2df62ee96 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -37,11 +37,11 @@ namespace v8 { namespace internal { AstSentinels::AstSentinels() - : this_proxy_(true), - identifier_proxy_(false), - valid_left_hand_side_sentinel_(), - this_property_(&this_proxy_, NULL, 0), - call_sentinel_(NULL, NULL, 0) { + : this_proxy_(Isolate::Current(), true), + identifier_proxy_(Isolate::Current(), false), + valid_left_hand_side_sentinel_(Isolate::Current()), + this_property_(Isolate::Current(), &this_proxy_, NULL, 0), + call_sentinel_(Isolate::Current(), NULL, NULL, 0) { } @@ -72,8 +72,9 @@ CountOperation* ExpressionStatement::StatementAsCountOperation() { } -VariableProxy::VariableProxy(Variable* var) - : name_(var->name()), +VariableProxy::VariableProxy(Isolate* isolate, Variable* var) + : Expression(isolate), + name_(var->name()), var_(NULL), // Will be set by the call to BindTo. is_this_(var->is_this()), 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 inside_with, int position) - : name_(name), - var_(NULL), - is_this_(is_this), - inside_with_(inside_with), - is_trivial_(false), - position_(position) { + : Expression(isolate), + name_(name), + var_(NULL), + is_this_(is_this), + inside_with_(inside_with), + is_trivial_(false), + position_(position) { // Names must be canonicalized for fast equality checks. ASSERT(name->IsSymbol()); } -VariableProxy::VariableProxy(bool is_this) - : var_(NULL), - is_this_(is_this), - inside_with_(false), - is_trivial_(false) { +VariableProxy::VariableProxy(Isolate* isolate, bool is_this) + : Expression(isolate), + var_(NULL), + is_this_(is_this), + 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* value, int pos) - : op_(op), + : Expression(isolate), + op_(op), target_(target), value_(value), pos_(pos), binary_operation_(NULL), compound_load_id_(kNoNumber), - assignment_id_(GetNextId()), + assignment_id_(GetNextId(isolate)), block_start_(false), block_end_(false), is_monomorphic_(false), @@ -138,8 +144,12 @@ Assignment::Assignment(Token::Value op, ASSERT(Token::IsAssignmentOp(op)); if (is_compound()) { binary_operation_ = - new BinaryOperation(binary_op(), target, value, pos + 1); - compound_load_id_ = GetNextId(); + new(isolate->zone()) BinaryOperation(isolate, + 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) { + Isolate* isolate = Isolate::Current(); emit_store_ = true; - key_ = new Literal(value->name()); + key_ = new(isolate->zone()) Literal(isolate, value->name()); value_ = value; 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, int pos) : label_(label), statements_(statements), position_(pos), compare_type_(NONE), - compare_id_(AstNode::GetNextId()), - entry_id_(AstNode::GetNextId()) { + compare_id_(AstNode::GetNextId(isolate)), + entry_id_(AstNode::GetNextId(isolate)) { } } } // namespace v8::internal diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 27d82cb34..23df48b8b 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -134,11 +134,15 @@ class AstNode: public ZoneObject { static const int kNoNumber = -1; static const int kFunctionEntryId = 2; // Using 0 could disguise errors. - AstNode() { - Isolate* isolate = Isolate::Current(); + // Override ZoneObject's new to count allocated AST nodes. + void* operator new(size_t size, Zone* zone) { + Isolate* isolate = zone->isolate(); isolate->set_ast_node_count(isolate->ast_node_count() + 1); + return zone->New(static_cast<int>(size)); } + AstNode() {} + virtual ~AstNode() { } virtual void Accept(AstVisitor* v) = 0; @@ -165,14 +169,21 @@ class AstNode: public ZoneObject { static void ResetIds() { Isolate::Current()->set_ast_node_id(0); } protected: - static unsigned GetNextId() { return ReserveIdRange(1); } - static unsigned ReserveIdRange(int n) { - Isolate* isolate = Isolate::Current(); + static unsigned GetNextId(Isolate* isolate) { + return ReserveIdRange(isolate, 1); + } + + static unsigned ReserveIdRange(Isolate* isolate, int n) { unsigned tmp = isolate->ast_node_id(); isolate->set_ast_node_id(tmp + n); 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. }; @@ -210,7 +221,9 @@ class Expression: public AstNode { kTest }; - Expression() : id_(GetNextId()), test_id_(GetNextId()) {} + explicit Expression(Isolate* isolate) + : id_(GetNextId(isolate)), + test_id_(GetNextId(isolate)) {} virtual int position() const { UNREACHABLE(); @@ -277,6 +290,7 @@ class Expression: public AstNode { */ class ValidLeftHandSideSentinel: public Expression { public: + explicit ValidLeftHandSideSentinel(Isolate* isolate) : Expression(isolate) {} virtual bool IsValidLeftHandSide() { return true; } virtual void Accept(AstVisitor* v) { UNREACHABLE(); } virtual bool IsInlineable() const; @@ -308,7 +322,7 @@ class BreakableStatement: public Statement { int ExitId() const { return exit_id_; } protected: - inline BreakableStatement(ZoneStringList* labels, Type type); + BreakableStatement(Isolate* isolate, ZoneStringList* labels, Type type); private: ZoneStringList* labels_; @@ -321,7 +335,10 @@ class BreakableStatement: public Statement { class Block: public BreakableStatement { 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) @@ -389,7 +406,7 @@ class IterationStatement: public BreakableStatement { Label* continue_target() { return &continue_target_; } protected: - explicit inline IterationStatement(ZoneStringList* labels); + inline IterationStatement(Isolate* isolate, ZoneStringList* labels); void Initialize(Statement* body) { body_ = body; @@ -404,7 +421,7 @@ class IterationStatement: public BreakableStatement { class DoWhileStatement: public IterationStatement { public: - explicit inline DoWhileStatement(ZoneStringList* labels); + inline DoWhileStatement(Isolate* isolate, ZoneStringList* labels); DECLARE_NODE_TYPE(DoWhileStatement) @@ -437,7 +454,7 @@ class DoWhileStatement: public IterationStatement { class WhileStatement: public IterationStatement { public: - explicit inline WhileStatement(ZoneStringList* labels); + inline WhileStatement(Isolate* isolate, ZoneStringList* labels); DECLARE_NODE_TYPE(WhileStatement) @@ -470,7 +487,7 @@ class WhileStatement: public IterationStatement { class ForStatement: public IterationStatement { public: - explicit inline ForStatement(ZoneStringList* labels); + inline ForStatement(Isolate* isolate, ZoneStringList* labels); DECLARE_NODE_TYPE(ForStatement) @@ -519,7 +536,7 @@ class ForStatement: public IterationStatement { class ForInStatement: public IterationStatement { public: - explicit inline ForInStatement(ZoneStringList* labels); + inline ForInStatement(Isolate* isolate, ZoneStringList* labels); DECLARE_NODE_TYPE(ForInStatement) @@ -636,7 +653,10 @@ class ExitContextStatement: public Statement { class CaseClause: public ZoneObject { 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; } Expression* label() const { @@ -671,7 +691,7 @@ class CaseClause: public ZoneObject { class SwitchStatement: public BreakableStatement { public: - explicit inline SwitchStatement(ZoneStringList* labels); + inline SwitchStatement(Isolate* isolate, ZoneStringList* labels); DECLARE_NODE_TYPE(SwitchStatement) @@ -697,15 +717,16 @@ class SwitchStatement: public BreakableStatement { // given if-statement has a then- or an else-part containing code. class IfStatement: public Statement { public: - IfStatement(Expression* condition, + IfStatement(Isolate* isolate, + Expression* condition, Statement* then_statement, Statement* else_statement) : condition_(condition), then_statement_(then_statement), else_statement_(else_statement), - if_id_(GetNextId()), - then_id_(GetNextId()), - else_id_(GetNextId()) { + if_id_(GetNextId(isolate)), + then_id_(GetNextId(isolate)), + else_id_(GetNextId(isolate)) { } DECLARE_NODE_TYPE(IfStatement) @@ -834,7 +855,8 @@ class EmptyStatement: public Statement { class Literal: public Expression { public: - explicit Literal(Handle<Object> handle) : handle_(handle) { } + Literal(Isolate* isolate, Handle<Object> handle) + : Expression(isolate), handle_(handle) { } DECLARE_NODE_TYPE(Literal) @@ -887,8 +909,14 @@ class Literal: public Expression { // Base class for literals that needs space in the corresponding JSFunction. class MaterializedLiteral: public Expression { public: - explicit MaterializedLiteral(int literal_index, bool is_simple, int depth) - : literal_index_(literal_index), is_simple_(is_simple), depth_(depth) {} + MaterializedLiteral(Isolate* isolate, + 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; } @@ -944,14 +972,15 @@ class ObjectLiteral: public MaterializedLiteral { bool emit_store_; }; - ObjectLiteral(Handle<FixedArray> constant_properties, + ObjectLiteral(Isolate* isolate, + Handle<FixedArray> constant_properties, ZoneList<Property*>* properties, int literal_index, bool is_simple, bool fast_elements, int depth, bool has_function) - : MaterializedLiteral(literal_index, is_simple, depth), + : MaterializedLiteral(isolate, literal_index, is_simple, depth), constant_properties_(constant_properties), properties_(properties), fast_elements_(fast_elements), @@ -990,10 +1019,11 @@ class ObjectLiteral: public MaterializedLiteral { // Node for capturing a regexp literal. class RegExpLiteral: public MaterializedLiteral { public: - RegExpLiteral(Handle<String> pattern, + RegExpLiteral(Isolate* isolate, + Handle<String> pattern, Handle<String> flags, int literal_index) - : MaterializedLiteral(literal_index, false, 1), + : MaterializedLiteral(isolate, literal_index, false, 1), pattern_(pattern), flags_(flags) {} @@ -1011,15 +1041,16 @@ class RegExpLiteral: public MaterializedLiteral { // for minimizing the work when constructing it at runtime. class ArrayLiteral: public MaterializedLiteral { public: - ArrayLiteral(Handle<FixedArray> constant_elements, + ArrayLiteral(Isolate* isolate, + Handle<FixedArray> constant_elements, ZoneList<Expression*>* values, int literal_index, bool is_simple, int depth) - : MaterializedLiteral(literal_index, is_simple, depth), + : MaterializedLiteral(isolate, literal_index, is_simple, depth), constant_elements_(constant_elements), values_(values), - first_element_id_(ReserveIdRange(values->length())) {} + first_element_id_(ReserveIdRange(isolate, values->length())) {} DECLARE_NODE_TYPE(ArrayLiteral) @@ -1038,7 +1069,7 @@ class ArrayLiteral: public MaterializedLiteral { class VariableProxy: public Expression { public: - explicit VariableProxy(Variable* var); + VariableProxy(Isolate* isolate, Variable* var); DECLARE_NODE_TYPE(VariableProxy) @@ -1085,11 +1116,12 @@ class VariableProxy: public Expression { bool is_trivial_; int position_; - VariableProxy(Handle<String> name, + VariableProxy(Isolate* isolate, + Handle<String> name, bool is_this, bool inside_with, int position = RelocInfo::kNoPosition); - explicit VariableProxy(bool is_this); + VariableProxy(Isolate* isolate, bool is_this); friend class Scope; }; @@ -1100,7 +1132,8 @@ class VariableProxySentinel: public VariableProxy { virtual bool IsValidLeftHandSide() { return !is_this(); } private: - explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { } + VariableProxySentinel(Isolate* isolate, bool is_this) + : VariableProxy(isolate, is_this) { } friend class AstSentinels; }; @@ -1130,8 +1163,8 @@ class Slot: public Expression { LOOKUP }; - Slot(Variable* var, Type type, int index) - : var_(var), type_(type), index_(index) { + Slot(Isolate* isolate, Variable* var, Type type, int index) + : Expression(isolate), var_(var), type_(type), index_(index) { ASSERT(var != NULL); } @@ -1162,8 +1195,13 @@ class Property: public Expression { // properties should use the global object as receiver, not the base object // of the resolved Reference. enum Type { NORMAL, SYNTHETIC }; - Property(Expression* obj, Expression* key, int pos, Type type = NORMAL) - : obj_(obj), + Property(Isolate* isolate, + Expression* obj, + Expression* key, + int pos, + Type type = NORMAL) + : Expression(isolate), + obj_(obj), key_(key), pos_(pos), type_(type), @@ -1215,14 +1253,18 @@ class Property: public Expression { class Call: public Expression { public: - Call(Expression* expression, ZoneList<Expression*>* arguments, int pos) - : expression_(expression), + Call(Isolate* isolate, + Expression* expression, + ZoneList<Expression*>* arguments, + int pos) + : Expression(isolate), + expression_(expression), arguments_(arguments), pos_(pos), is_monomorphic_(false), check_type_(RECEIVER_MAP_CHECK), receiver_types_(NULL), - return_id_(GetNextId()) { + return_id_(GetNextId(isolate)) { } DECLARE_NODE_TYPE(Call) @@ -1301,8 +1343,14 @@ class AstSentinels { class CallNew: public Expression { public: - CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos) - : expression_(expression), arguments_(arguments), pos_(pos) { } + CallNew(Isolate* isolate, + Expression* expression, + ZoneList<Expression*>* arguments, + int pos) + : Expression(isolate), + expression_(expression), + arguments_(arguments), + pos_(pos) { } DECLARE_NODE_TYPE(CallNew) @@ -1325,10 +1373,14 @@ class CallNew: public Expression { // implemented in JavaScript (see "v8natives.js"). class CallRuntime: public Expression { public: - CallRuntime(Handle<String> name, + CallRuntime(Isolate* isolate, + Handle<String> name, const Runtime::Function* function, ZoneList<Expression*>* arguments) - : name_(name), function_(function), arguments_(arguments) { } + : Expression(isolate), + name_(name), + function_(function), + arguments_(arguments) { } DECLARE_NODE_TYPE(CallRuntime) @@ -1348,8 +1400,11 @@ class CallRuntime: public Expression { class UnaryOperation: public Expression { public: - UnaryOperation(Token::Value op, Expression* expression, int pos) - : op_(op), expression_(expression), pos_(pos) { + UnaryOperation(Isolate* isolate, + Token::Value op, + Expression* expression, + int pos) + : Expression(isolate), op_(op), expression_(expression), pos_(pos) { ASSERT(Token::IsUnaryOp(op)); } @@ -1372,14 +1427,15 @@ class UnaryOperation: public Expression { class BinaryOperation: public Expression { public: - BinaryOperation(Token::Value op, + BinaryOperation(Isolate* isolate, + Token::Value op, Expression* left, Expression* right, int pos) - : op_(op), left_(left), right_(right), pos_(pos) { + : Expression(isolate), op_(op), left_(left), right_(right), pos_(pos) { ASSERT(Token::IsBinaryOp(op)); right_id_ = (op == Token::AND || op == Token::OR) - ? static_cast<int>(GetNextId()) + ? static_cast<int>(GetNextId(isolate)) : AstNode::kNoNumber; } @@ -1410,13 +1466,18 @@ class BinaryOperation: public Expression { class CountOperation: public Expression { public: - CountOperation(Token::Value op, bool is_prefix, Expression* expr, int pos) - : op_(op), + CountOperation(Isolate* isolate, + Token::Value op, + bool is_prefix, + Expression* expr, + int pos) + : Expression(isolate), + op_(op), is_prefix_(is_prefix), expression_(expr), pos_(pos), - assignment_id_(GetNextId()), - count_id_(GetNextId()), + assignment_id_(GetNextId(isolate)), + count_id_(GetNextId(isolate)), receiver_types_(NULL) { } DECLARE_NODE_TYPE(CountOperation) @@ -1462,11 +1523,17 @@ class CountOperation: public Expression { class CompareOperation: public Expression { public: - CompareOperation(Token::Value op, + CompareOperation(Isolate* isolate, + Token::Value op, Expression* left, Expression* right, 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)); } @@ -1501,8 +1568,8 @@ class CompareOperation: public Expression { class CompareToNull: public Expression { public: - CompareToNull(bool is_strict, Expression* expression) - : is_strict_(is_strict), expression_(expression) { } + CompareToNull(Isolate* isolate, bool is_strict, Expression* expression) + : Expression(isolate), is_strict_(is_strict), expression_(expression) { } DECLARE_NODE_TYPE(CompareToNull) @@ -1520,18 +1587,20 @@ class CompareToNull: public Expression { class Conditional: public Expression { public: - Conditional(Expression* condition, + Conditional(Isolate* isolate, + Expression* condition, Expression* then_expression, Expression* else_expression, int then_expression_position, int else_expression_position) - : condition_(condition), + : Expression(isolate), + condition_(condition), then_expression_(then_expression), else_expression_(else_expression), then_expression_position_(then_expression_position), else_expression_position_(else_expression_position), - then_id_(GetNextId()), - else_id_(GetNextId()) { + then_id_(GetNextId(isolate)), + else_id_(GetNextId(isolate)) { } DECLARE_NODE_TYPE(Conditional) @@ -1561,7 +1630,11 @@ class Conditional: public Expression { class Assignment: public Expression { 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) @@ -1621,8 +1694,8 @@ class Assignment: public Expression { class Throw: public Expression { public: - Throw(Expression* exception, int pos) - : exception_(exception), pos_(pos) {} + Throw(Isolate* isolate, Expression* exception, int pos) + : Expression(isolate), exception_(exception), pos_(pos) {} DECLARE_NODE_TYPE(Throw) @@ -1638,7 +1711,8 @@ class Throw: public Expression { class FunctionLiteral: public Expression { public: - FunctionLiteral(Handle<String> name, + FunctionLiteral(Isolate* isolate, + Handle<String> name, Scope* scope, ZoneList<Statement*>* body, int materialized_literal_count, @@ -1650,7 +1724,8 @@ class FunctionLiteral: public Expression { int end_position, bool is_expression, bool has_duplicate_parameters) - : name_(name), + : Expression(isolate), + name_(name), scope_(scope), body_(body), materialized_literal_count_(materialized_literal_count), @@ -1729,9 +1804,10 @@ class FunctionLiteral: public Expression { class SharedFunctionInfoLiteral: public Expression { public: - explicit SharedFunctionInfoLiteral( + SharedFunctionInfoLiteral( + Isolate* isolate, Handle<SharedFunctionInfo> shared_function_info) - : shared_function_info_(shared_function_info) { } + : Expression(isolate), shared_function_info_(shared_function_info) { } DECLARE_NODE_TYPE(SharedFunctionInfoLiteral) @@ -1747,6 +1823,7 @@ class SharedFunctionInfoLiteral: public Expression { class ThisFunction: public Expression { public: + explicit ThisFunction(Isolate* isolate) : Expression(isolate) {} DECLARE_NODE_TYPE(ThisFunction) virtual bool IsInlineable() const; }; diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 8e34b9cf5..8cca5614b 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1309,6 +1309,7 @@ void Genesis::InstallNativeFunctions() { void Genesis::InstallExperimentalNativeFunctions() { if (FLAG_harmony_proxies) { + INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap); INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap); INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap); } diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 6a44d8cae..d403a951c 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -1202,10 +1202,10 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor( ASSERT(!CalledAsConstructor(isolate)); Heap* heap = isolate->heap(); - Handle<Object> receiver = args.at<Object>(0); + Handle<Object> receiver = args.receiver(); // 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 // used to create the called object. diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 5c0ef5a4a..1d1128f2d 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -250,7 +250,7 @@ void KeyedLoadElementStub::Generate(MacroAssembler* masm) { KeyedLoadStubCompiler::GenerateLoadFastElement(masm); break; case JSObject::FAST_DOUBLE_ELEMENTS: - UNIMPLEMENTED(); + KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(masm); break; case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: @@ -279,7 +279,8 @@ void KeyedStoreElementStub::Generate(MacroAssembler* masm) { KeyedStoreStubCompiler::GenerateStoreFastElement(masm, is_js_array_); break; case JSObject::FAST_DOUBLE_ELEMENTS: - UNIMPLEMENTED(); + KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm, + is_js_array_); break; case JSObject::EXTERNAL_BYTE_ELEMENTS: case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index e09b72f7d..c265b95ac 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -511,7 +511,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, info.SetPreParseData(pre_data); if (natives == NATIVES_CODE) { info.MarkAsAllowingNativesSyntax(); - info.MarkAsNative(); } result = MakeFunctionInfo(&info); if (extension == NULL && !result.is_null()) { @@ -679,7 +678,6 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, info.SetFunction(literal); info.SetScope(literal->scope()); if (literal->scope()->is_strict_mode()) info.MarkAsStrictMode(); - if (script->type()->value() == Script::TYPE_NATIVE) info.MarkAsNative(); LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal); // Determine if the function can be lazily compiled. This is necessary to diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h index a77fc8ea4..8e92cf5a1 100644 --- a/deps/v8/src/compiler.h +++ b/deps/v8/src/compiler.h @@ -173,9 +173,12 @@ class CompilationInfo BASE_EMBEDDED { void Initialize(Mode mode) { mode_ = V8::UseCrankshaft() ? mode : NONOPT; - if (!shared_info_.is_null()) { - if (shared_info_->strict_mode()) MarkAsStrictMode(); - if (shared_info_->native()) MarkAsNative(); + ASSERT(!script_.is_null()); + if (script_->type()->value() == Script::TYPE_NATIVE) { + MarkAsNative(); + } + if (!shared_info_.is_null() && shared_info_->strict_mode()) { + MarkAsStrictMode(); } } diff --git a/deps/v8/src/contexts.h b/deps/v8/src/contexts.h index 0f3d44cc2..53b40f127 100644 --- a/deps/v8/src/contexts.h +++ b/deps/v8/src/contexts.h @@ -110,6 +110,7 @@ enum ContextLookupFlags { V(MAP_CACHE_INDEX, Object, map_cache) \ V(CONTEXT_DATA_INDEX, Object, data) \ 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_SET_TRAP_INDEX, JSFunction, derived_set_trap) @@ -227,6 +228,7 @@ class Context: public FixedArray { OUT_OF_MEMORY_INDEX, CONTEXT_DATA_INDEX, ALLOW_CODE_GEN_FROM_STRINGS_INDEX, + DERIVED_HAS_TRAP_INDEX, DERIVED_GET_TRAP_INDEX, DERIVED_SET_TRAP_INDEX, diff --git a/deps/v8/src/conversions-inl.h b/deps/v8/src/conversions-inl.h index f1f526ffc..b82863856 100644 --- a/deps/v8/src/conversions-inl.h +++ b/deps/v8/src/conversions-inl.h @@ -454,7 +454,6 @@ static double InternalStringToDouble(UnicodeCache* unicode_cache, int significant_digits = 0; int insignificant_digits = 0; bool nonzero_digit_dropped = false; - bool fractional_part = false; bool negative = false; @@ -557,10 +556,8 @@ static double InternalStringToDouble(UnicodeCache* unicode_cache, } } - // We don't emit a '.', but adjust the exponent instead. - fractional_part = true; - - // There is a fractional part. + // There is a fractional part. We don't emit a '.', but adjust the exponent + // instead. while (*current >= '0' && *current <= '9') { if (significant_digits < kMaxSignificantDigits) { ASSERT(buffer_pos < kBufferSize); diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 5f5735009..4917f7d64 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -26,33 +26,49 @@ // 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 #include <bzlib.h> #endif + #include <errno.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" + +#ifndef USING_V8_SHARED +#include "api.h" +#include "checks.h" #include "d8-debug.h" #include "debug.h" -#include "api.h" #include "natives.h" #include "platform.h" +#include "v8.h" +#endif // USING_V8_SHARED #if !defined(_WIN32) && !defined(_WIN64) #include <unistd.h> // NOLINT #endif -namespace v8 { - +#ifdef USING_V8_SHARED +#define ASSERT(condition) assert(condition) +#endif // USING_V8_SHARED -const char* Shell::kHistoryFileName = ".d8_history"; -const char* Shell::kPrompt = "d8> "; +namespace v8 { +#ifndef USING_V8_SHARED LineEditor *LineEditor::first_ = NULL; +const char* Shell::kHistoryFileName = ".d8_history"; LineEditor::LineEditor(Type type, const char* name) @@ -98,17 +114,22 @@ CounterMap* Shell::counter_map_; i::OS::MemoryMappedFile* Shell::counters_file_ = NULL; CounterCollection Shell::local_counters_; CounterCollection* Shell::counters_ = &local_counters_; +i::Mutex* Shell::context_mutex_(i::OS::CreateMutex()); Persistent<Context> Shell::utility_context_; +#endif // USING_V8_SHARED + Persistent<Context> Shell::evaluation_context_; -i::Mutex* Shell::context_mutex_(i::OS::CreateMutex()); ShellOptions Shell::options; +const char* Shell::kPrompt = "d8> "; +#ifndef USING_V8_SHARED bool CounterMap::Match(void* key1, void* key2) { const char* name1 = reinterpret_cast<const char*>(key1); const char* name2 = reinterpret_cast<const char*>(key2); return strcmp(name1, name2) == 0; } +#endif // USING_V8_SHARED // Converts a V8 value to a C string. @@ -122,17 +143,22 @@ bool Shell::ExecuteString(Handle<String> source, Handle<Value> name, bool print_result, 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; TryCatch try_catch; options.script_executed = true; - if (i::FLAG_debugger) { + if (FLAG_debugger) { // When debugging make exceptions appear to be uncaught. try_catch.SetVerbose(true); } Handle<Script> script = Script::Compile(source, name); if (script.IsEmpty()) { // Print errors that happened during compilation. - if (report_exceptions && !i::FLAG_debugger) + if (report_exceptions && !FLAG_debugger) ReportException(&try_catch); return false; } else { @@ -140,7 +166,7 @@ bool Shell::ExecuteString(Handle<String> source, if (result.IsEmpty()) { ASSERT(try_catch.HasCaught()); // Print errors that happened during execution. - if (report_exceptions && !i::FLAG_debugger) + if (report_exceptions && !FLAG_debugger) ReportException(&try_catch); return false; } else { @@ -161,6 +187,7 @@ bool Shell::ExecuteString(Handle<String> source, Handle<Value> Shell::Print(const Arguments& args) { Handle<Value> val = Write(args); printf("\n"); + fflush(stdout); return val; } @@ -196,15 +223,20 @@ Handle<Value> Shell::Read(const Arguments& args) { Handle<Value> Shell::ReadLine(const Arguments& args) { - i::SmartPointer<char> line(i::ReadLine("")); - if (*line == NULL) { - return Null(); - } - size_t len = strlen(*line); - if (len > 0 && line[len - 1] == '\n') { - --len; - } - return String::New(*line, len); + static const int kBufferSize = 256; + char buffer[kBufferSize]; + Handle<String> accumulator = String::New(""); + bool linebreak; + int length; + do { // Repeat if the line ends with an escape '\'. + // fgets got an error. Just give up. + if (fgets(buffer, kBufferSize, stdin) == NULL) return Null(); + 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( 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; if (args[0]->IsUint32()) { length = args[0]->Uint32Value(); @@ -244,7 +280,7 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, if (raw_length < 0) { return ThrowException(String::New("Array length must not be negative.")); } - if (raw_length > i::ExternalArray::kMaxLength) { + if (raw_length > kMaxLength) { return ThrowException( String::New("Array length exceeds maximum length.")); } @@ -252,7 +288,7 @@ Handle<Value> Shell::CreateExternalArray(const Arguments& args, } else { 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.")); } void* data = calloc(length, element_size); @@ -332,7 +368,9 @@ Handle<Value> Shell::Yield(const Arguments& args) { Handle<Value> Shell::Quit(const Arguments& args) { int exit_code = args[0]->Int32Value(); +#ifndef USING_V8_SHARED OnExit(); +#endif // USING_V8_SHARED exit(exit_code); 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) { HandleScope handle_scope; 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); 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) { int i; for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) @@ -448,8 +489,8 @@ Counter* CounterCollection::GetNextCounter() { void Shell::MapCounters(const char* name) { - counters_file_ = i::OS::MemoryMappedFile::create(name, - sizeof(CounterCollection), &local_counters_); + counters_file_ = i::OS::MemoryMappedFile::create( + name, sizeof(CounterCollection), &local_counters_); void* memory = (counters_file_ == NULL) ? NULL : counters_file_->memory(); if (memory == NULL) { @@ -514,6 +555,7 @@ void Shell::AddHistogramSample(void* histogram, int sample) { counter->AddSample(sample); } + void Shell::InstallUtilityScript() { Locker lock; HandleScope scope; @@ -532,7 +574,7 @@ void Shell::InstallUtilityScript() { utility_context_->Global()->Set(String::New("$debug"), Utils::ToLocal(js_debug)); debug->debug_context()->set_security_token(HEAP->undefined_value()); -#endif +#endif // ENABLE_DEBUGGER_SUPPORT // Run the d8 shell utility script in the utility context int source_index = i::NativesCollection<i::D8>::GetIndex("d8"); @@ -550,10 +592,10 @@ void Shell::InstallUtilityScript() { // in the debugger. i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script); i::Handle<i::Script> script_object = compiled_script->IsJSFunction() - ? i::Handle<i::Script>(i::Script::cast( - i::JSFunction::cast(*compiled_script)->shared()->script())) - : i::Handle<i::Script>(i::Script::cast( - i::SharedFunctionInfo::cast(*compiled_script)->script())); + ? i::Handle<i::Script>(i::Script::cast( + i::JSFunction::cast(*compiled_script)->shared()->script())) + : i::Handle<i::Script>(i::Script::cast( + i::SharedFunctionInfo::cast(*compiled_script)->script())); script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE)); #ifdef ENABLE_DEBUGGER_SUPPORT @@ -561,8 +603,9 @@ void Shell::InstallUtilityScript() { if (i::FLAG_debugger && !i::FLAG_debugger_agent) { v8::Debug::SetDebugEventListener(HandleDebugEvent); } -#endif +#endif // ENABLE_DEBUGGER_SUPPORT } +#endif // USING_V8_SHARED #ifdef COMPRESS_STARTUP_DATA_BZ2 @@ -629,9 +672,11 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { global_template->Set(String::New("lol_is_enabled"), Boolean::New(false)); #endif +#ifndef USING_V8_SHARED Handle<ObjectTemplate> os_templ = ObjectTemplate::New(); AddOSMethods(os_templ); global_template->Set(String::New("os"), os_templ); +#endif // USING_V8_SHARED return global_template; } @@ -647,6 +692,7 @@ void Shell::Initialize() { } #endif +#ifndef USING_V8_SHARED Shell::counter_map_ = new CounterMap(); // Set up counters if (i::StrLength(i::FLAG_map_counters) != 0) @@ -656,9 +702,10 @@ void Shell::Initialize() { V8::SetCreateHistogramFunction(CreateHistogram); V8::SetAddHistogramSampleFunction(AddHistogramSample); } - +#endif // USING_V8_SHARED if (options.test_shell) return; +#ifndef USING_V8_SHARED Locker lock; HandleScope scope; Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); @@ -669,18 +716,22 @@ void Shell::Initialize() { if (i::FLAG_debugger_agent) { v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true); } -#endif +#endif // ENABLE_DEBUGGER_SUPPORT +#endif // USING_V8_SHARED } Persistent<Context> Shell::CreateEvaluationContext() { +#ifndef USING_V8_SHARED // This needs to be a critical section since this is not thread-safe i::ScopedLock lock(context_mutex_); +#endif // USING_V8_SHARED // Initialize the global objects Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); Persistent<Context> context = Context::New(NULL, global_template); Context::Scope scope(context); +#ifndef USING_V8_SHARED i::JSArguments js_args = i::FLAG_js_arguments; i::Handle<i::FixedArray> arguments_array = FACTORY->NewFixedArray(js_args.argc()); @@ -692,11 +743,13 @@ Persistent<Context> Shell::CreateEvaluationContext() { i::Handle<i::JSArray> arguments_jsarray = FACTORY->NewJSArrayWithElements(arguments_array); context->Global()->Set(String::New("arguments"), - Utils::ToLocal(arguments_jsarray)); + Utils::ToLocal(arguments_jsarray)); +#endif // USING_V8_SHARED return context; } +#ifndef USING_V8_SHARED void Shell::OnExit() { if (i::FLAG_dump_counters) { printf("+----------------------------------------+-------------+\n"); @@ -716,12 +769,18 @@ void Shell::OnExit() { if (counters_file_ != NULL) delete counters_file_; } +#endif // USING_V8_SHARED static char* ReadChars(const char* name, int* size_out) { // Release the V8 lock while reading files. v8::Unlocker unlocker(Isolate::GetCurrent()); +#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"); +#endif // USING_V8_SHARED if (file == NULL) return NULL; 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) { char* next = i::OS::StrChr(data, token); if (next != NULL) { @@ -759,6 +819,7 @@ static char* ReadLine(char* data) { static char* ReadWord(char* data) { return ReadToken(data, ' '); } +#endif // USING_V8_SHARED // Reads a file into a v8 string. @@ -773,34 +834,44 @@ Handle<String> Shell::ReadFile(const char* name) { 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(); printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name()); if (i::FLAG_debugger) { printf("JavaScript debugger enabled\n"); } - editor->Open(); while (true) { - Locker locker; - HandleScope handle_scope; - Context::Scope context_scope(evaluation_context_); i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt); - if (input.is_empty()) - break; + if (input.is_empty()) break; editor->AddHistory(*input); - Handle<String> name = String::New("(d8)"); ExecuteString(String::New(*input), name, true, true); } editor->Close(); +#else + printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion()); + static const int kBufferSize = 256; + 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"); } +#ifndef USING_V8_SHARED class ShellThread : public i::Thread { public: ShellThread(int no, i::Vector<const char> files) - : Thread("d8:ShellThread"), - no_(no), files_(files) { } + : Thread("d8:ShellThread"), + no_(no), files_(files) { } virtual void Run(); private: int no_; @@ -848,6 +919,7 @@ void ShellThread::Run() { ptr = next_line; } } +#endif // USING_V8_SHARED void SourceGroup::ExitShell(int exit_code) { @@ -894,7 +966,12 @@ void SourceGroup::Execute() { 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"); +#endif // USING_V8_SHARED if (file == NULL) return Handle<String>(); 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 options; options.name = "IsolateThread"; @@ -965,6 +1043,7 @@ void SourceGroup::WaitForThread() { done_semaphore_->Wait(); } } +#endif // USING_V8_SHARED bool Shell::SetOptions(int argc, char* argv[]) { @@ -986,12 +1065,26 @@ bool Shell::SetOptions(int argc, char* argv[]) { options.test_shell = true; argv[i] = NULL; } 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; argv[i] = NULL; +#endif // USING_V8_SHARED } 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; argv[i] = NULL; +#endif // USING_V8_SHARED } 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) { argv[i-1] = NULL; char* end = NULL; @@ -1007,15 +1100,33 @@ bool Shell::SetOptions(int argc, char* argv[]) { printf("Missing value for --preemption-interval\n"); return false; } +#endif // USING_V8_SHARED } else if (strcmp(argv[i], "-f") == 0) { // Ignore any -f flags for compatibility with other stand-alone // JavaScript engines. continue; } 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++; } +#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 for (int i = 1; i < argc; i++) { 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)); } } +#endif // USING_V8_SHARED v8::V8::SetFlagsFromCommandLine(&argc, argv, true); @@ -1062,21 +1174,21 @@ bool Shell::SetOptions(int argc, char* argv[]) { int Shell::RunMain(int argc, char* argv[]) { +#ifndef USING_V8_SHARED i::List<i::Thread*> threads(1); - - { - if (options.parallel_files != NULL) - for (int i = 0; i < options.parallel_files->length(); i++) { - i::Vector<const char> files = options.parallel_files->at(i); - ShellThread* thread = new ShellThread(threads.length(), files); - thread->Start(); - threads.Add(thread); - } - - for (int i = 1; i < options.num_isolates; ++i) { - options.isolate_sources[i].StartExecuteInThread(); + if (options.parallel_files != NULL) + for (int i = 0; i < options.parallel_files->length(); i++) { + i::Vector<const char> files = options.parallel_files->at(i); + ShellThread* thread = new ShellThread(threads.length(), files); + thread->Start(); + threads.Add(thread); } + for (int i = 1; i < options.num_isolates; ++i) { + options.isolate_sources[i].StartExecuteInThread(); + } +#endif // USING_V8_SHARED + { // NOLINT Locker lock; HandleScope scope; Persistent<Context> context = CreateEvaluationContext(); @@ -1090,14 +1202,18 @@ int Shell::RunMain(int argc, char* argv[]) { } else { context.Dispose(); } + +#ifndef USING_V8_SHARED // Start preemption if threads have been created and preemption is enabled. if (options.parallel_files != NULL && threads.length() > 0 && options.use_preemption) { Locker::StartPreemption(options.preemption_interval); } +#endif // USING_V8_SHARED } +#ifndef USING_V8_SHARED for (int i = 1; i < options.num_isolates; ++i) { options.isolate_sources[i].WaitForThread(); } @@ -1110,6 +1226,7 @@ int Shell::RunMain(int argc, char* argv[]) { } OnExit(); +#endif // USING_V8_SHARED return 0; } @@ -1136,14 +1253,15 @@ int Shell::Main(int argc, char* 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 if (i::FLAG_remote_debugger && !options.test_shell) { InstallUtilityScript(); RunRemoteDebugger(i::FLAG_debugger_port); return 0; } -#endif +#endif // !USING_V8_SHARED && ENABLE_DEBUGGER_SUPPORT // Run interactive shell if explicitly requested or if no script has been // executed, but never on --test @@ -1151,7 +1269,9 @@ int Shell::Main(int argc, char* argv[]) { if (( options.interactive_shell || !options.script_executed ) && !options.test_shell ) { +#ifndef USING_V8_SHARED InstallUtilityScript(); +#endif // USING_V8_SHARED RunShell(); } diff --git a/deps/v8/src/d8.gyp b/deps/v8/src/d8.gyp index 85914ec67..d2b425403 100644 --- a/deps/v8/src/d8.gyp +++ b/deps/v8/src/d8.gyp @@ -26,12 +26,14 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. { + 'variables': { + 'console%': '', + }, 'targets': [ { 'target_name': 'd8', 'type': 'executable', 'dependencies': [ - 'd8_js2c#host', '../tools/gyp/v8.gyp:v8', ], 'include_dirs+': [ @@ -42,15 +44,24 @@ ], 'sources': [ 'd8.cc', - 'd8-debug.cc', - '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', ], 'conditions': [ - [ 'OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { - 'sources': [ 'd8-posix.cc', ] - }], - [ 'OS=="win"', { - 'sources': [ 'd8-windows.cc', ] + [ 'component!="shared_library"', { + 'dependencies': [ 'd8_js2c#host', ], + 'sources': [ 'd8-debug.cc', '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', ], + 'conditions': [ + [ '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', ] + }], + ], }], ], }, diff --git a/deps/v8/src/d8.h b/deps/v8/src/d8.h index 7f0272710..840ca1e8f 100644 --- a/deps/v8/src/d8.h +++ b/deps/v8/src/d8.h @@ -28,16 +28,23 @@ #ifndef V8_D8_H_ #define V8_D8_H_ -#include "allocation.h" + +#ifndef USING_V8_SHARED #include "v8.h" +#include "allocation.h" #include "hashmap.h" +#else +#include "../include/v8.h" +#endif // USING_V8_SHARED namespace v8 { - +#ifndef USING_V8_SHARED namespace i = v8::internal; +#endif // USING_V8_SHARED +#ifndef USING_V8_SHARED // A single counter in a counter collection. class Counter { public: @@ -110,17 +117,20 @@ class CounterMap { static bool Match(void* key1, void* key2); i::HashMap hash_map_; }; +#endif // USING_V8_SHARED class SourceGroup { public: - SourceGroup() - : next_semaphore_(v8::internal::OS::CreateSemaphore(0)), - done_semaphore_(v8::internal::OS::CreateSemaphore(0)), - thread_(NULL), - argv_(NULL), - begin_offset_(0), - end_offset_(0) { } + SourceGroup() : +#ifndef USING_V8_SHARED + next_semaphore_(v8::internal::OS::CreateSemaphore(0)), + done_semaphore_(v8::internal::OS::CreateSemaphore(0)), + thread_(NULL), +#endif // USING_V8_SHARED + argv_(NULL), + begin_offset_(0), + end_offset_(0) { } void Begin(char** argv, int offset) { argv_ = const_cast<const char**>(argv); @@ -131,6 +141,7 @@ class SourceGroup { void Execute(); +#ifndef USING_V8_SHARED void StartExecuteInThread(); void WaitForThread(); @@ -154,6 +165,7 @@ class SourceGroup { i::Semaphore* next_semaphore_; i::Semaphore* done_semaphore_; i::Thread* thread_; +#endif // USING_V8_SHARED void ExitShell(int exit_code); Handle<String> ReadFile(const char* name); @@ -166,34 +178,41 @@ class SourceGroup { class ShellOptions { public: - ShellOptions() - : script_executed(false), - last_run(true), - stress_opt(false), - stress_deopt(false), - interactive_shell(false), - test_shell(false), - use_preemption(true), - preemption_interval(10), - num_isolates(1), - isolate_sources(NULL), - parallel_files(NULL) { } - + ShellOptions() : +#ifndef USING_V8_SHARED + use_preemption(true), + preemption_interval(10), + parallel_files(NULL), +#endif // USING_V8_SHARED + script_executed(false), + last_run(true), + stress_opt(false), + stress_deopt(false), + interactive_shell(false), + 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 last_run; bool stress_opt; bool stress_deopt; bool interactive_shell; bool test_shell; - bool use_preemption; - int preemption_interval; int num_isolates; SourceGroup* isolate_sources; - i::List< i::Vector<const char> >* parallel_files; }; - -class Shell: public i::AllStatic { +#ifdef USING_V8_SHARED +class Shell { +#else +class Shell : public i::AllStatic { +#endif // USING_V8_SHARED public: static bool ExecuteString(Handle<String> source, Handle<Value> name, @@ -201,6 +220,14 @@ class Shell: public i::AllStatic { bool report_exceptions); static const char* ToCString(const v8::String::Utf8Value& value); 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 int* LookupCounter(const char* name); static void* CreateHistogram(const char* name, @@ -209,18 +236,8 @@ class Shell: public i::AllStatic { size_t buckets); static void AddHistogramSample(void* histogram, int sample); static void MapCounters(const char* name); - static Handle<String> ReadFile(const char* name); - 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); +#endif // USING_V8_SHARED + #ifdef ENABLE_DEBUGGER_SUPPORT static Handle<Object> DebugMessageDetails(Handle<String> message); static Handle<Value> DebugCommandToJSONRequest(Handle<String> command); @@ -283,15 +300,16 @@ class Shell: public i::AllStatic { static Handle<Value> RemoveDirectory(const Arguments& args); static void AddOSMethods(Handle<ObjectTemplate> os_template); - +#ifndef USING_V8_SHARED static const char* kHistoryFileName; +#endif // USING_V8_SHARED static const char* kPrompt; - static ShellOptions options; private: - static Persistent<Context> utility_context_; static Persistent<Context> evaluation_context_; +#ifndef USING_V8_SHARED + static Persistent<Context> utility_context_; static CounterMap* counter_map_; // 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 @@ -299,7 +317,14 @@ class Shell: public i::AllStatic { static CounterCollection* counters_; static i::OS::MemoryMappedFile* counters_file_; static i::Mutex* context_mutex_; + 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, ExternalArrayType type, size_t element_size); @@ -307,6 +332,7 @@ class Shell: public i::AllStatic { }; +#ifndef USING_V8_SHARED class LineEditor { public: enum Type { DUMB = 0, READLINE = 1 }; @@ -326,6 +352,7 @@ class LineEditor { LineEditor* next_; static LineEditor* first_; }; +#endif // USING_V8_SHARED } // namespace v8 diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index c48e514ab..aecbb463b 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -772,9 +772,9 @@ bool Debug::CompileDebuggerScript(int index) { bool caught_exception = false; Handle<JSFunction> function = factory->NewFunctionFromSharedFunctionInfo(function_info, context); - Handle<Object> result = - Execution::TryCall(function, Handle<Object>(context->global()), - 0, NULL, &caught_exception); + + Execution::TryCall(function, Handle<Object>(context->global()), + 0, NULL, &caught_exception); // Check for caught exceptions. if (caught_exception) { @@ -1886,8 +1886,7 @@ void Debug::ClearMirrorCache() { *function_name)); ASSERT(fun->IsJSFunction()); bool caught_exception; - Handle<Object> js_object = Execution::TryCall( - Handle<JSFunction>::cast(fun), + Execution::TryCall(Handle<JSFunction>::cast(fun), Handle<JSObject>(Debug::debug_context()->global()), 0, NULL, &caught_exception); } @@ -2252,8 +2251,7 @@ void Debugger::OnAfterCompile(Handle<Script> script, bool caught_exception = false; const int argc = 1; Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) }; - Handle<Object> result = Execution::TryCall( - Handle<JSFunction>::cast(update_script_break_points), + Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points), Isolate::Current()->js_builtins_object(), argc, argv, &caught_exception); if (caught_exception) { @@ -2930,7 +2928,7 @@ v8::Handle<v8::Context> MessageImpl::GetEventContext() const { v8::Handle<v8::Context> context = GetDebugEventContext(isolate); // Isolate::context() may be NULL when "script collected" event occures. ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected); - return GetDebugEventContext(isolate); + return context; } diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index 175ee6e1f..3a7b33a21 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -1462,7 +1462,7 @@ DeoptimizedFrameInfo::~DeoptimizedFrameInfo() { } void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { - v->VisitPointer(reinterpret_cast<Object**>(&function_)); + v->VisitPointer(BitCast<Object**>(&function_)); v->VisitPointers(parameters_, parameters_ + parameters_count_); v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); } diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index 9ba48ee50..ac96668d9 100644 --- a/deps/v8/src/factory.cc +++ b/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<String> name, int number_of_literals, diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 19f09a15c..19f382793 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -253,6 +253,9 @@ class Factory { 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<Object> prototype); diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index eaf09ebaf..bebd10a80 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -371,7 +371,6 @@ Code* StackFrame::GetSafepointData(Isolate* isolate, unsigned* stack_slots) { PcToCodeCache::PcToCodeCacheEntry* entry = isolate->pc_to_code_cache()->GetCacheEntry(pc); - SafepointEntry cached_safepoint_entry = entry->safepoint_entry; if (!entry->safepoint_entry.is_valid()) { entry->safepoint_entry = entry->code->GetSafepointEntry(pc); ASSERT(entry->safepoint_entry.is_valid()); diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc index 0b91f5446..8c2f0d178 100644 --- a/deps/v8/src/full-codegen.cc +++ b/deps/v8/src/full-codegen.cc @@ -686,7 +686,6 @@ FullCodeGenerator::InlineFunctionGenerator void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) { ZoneList<Expression*>* args = node->arguments(); - Handle<String> name = node->name(); const Runtime::Function* function = node->function(); ASSERT(function != NULL); ASSERT(function->intrinsic_type == Runtime::INLINE); diff --git a/deps/v8/src/globals.h b/deps/v8/src/globals.h index 5ab9806ed..bb9d0a8e8 100644 --- a/deps/v8/src/globals.h +++ b/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 // modification, are permitted provided that the following conditions are // met: @@ -199,6 +199,8 @@ const int kDoubleSize = sizeof(double); // NOLINT const int kIntptrSize = sizeof(intptr_t); // NOLINT const int kPointerSize = sizeof(void*); // NOLINT +const int kDoubleSizeLog2 = 3; + #if V8_HOST_ARCH_64_BIT const int kPointerSizeLog2 = 3; const intptr_t kIntptrSignBit = V8_INT64_C(0x8000000000000000); diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 98a2d3374..8dbda270f 100644 --- a/deps/v8/src/heap.cc +++ b/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); if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj; map->set_prototype(prototype); - map->set_pre_allocated_property_fields(1); - map->set_inobject_properties(1); // Allocate the proxy object. Object* result; MaybeObject* maybe_result = Allocate(map, NEW_SPACE); if (!maybe_result->ToObject(&result)) return maybe_result; JSProxy::cast(result)->set_handler(handler); + JSProxy::cast(result)->set_padding(Smi::FromInt(0)); 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, JSGlobalProxy* object) { ASSERT(constructor->has_initial_map()); diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index d90a681d4..6cd4f840b 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -441,6 +441,11 @@ class Heap { MUST_USE_RESULT MaybeObject* AllocateJSProxy(Object* handler, Object* prototype); + // Reinitialize a JSProxy into an (empty) JSObject. The receiver + // must have the same size as an empty object. The object is reinitialized + // and behaves as an object that has been freshly allocated. + MUST_USE_RESULT MaybeObject* ReinitializeJSProxyAsJSObject(JSProxy* object); + // Reinitialize an JSGlobalProxy based on a constructor. The object // must have the same size as objects allocated using the // constructor. The object is reinitialized and behaves as an diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index 50f2f6df6..d282f3781 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/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) { object()->PrintNameTo(stream); 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) { object()->PrintNameTo(stream); stream->Add("["); diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 401c2e4a0..15186ff26 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -131,6 +131,7 @@ class LChunkBuilder; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ + V(LoadKeyedFastDoubleElement) \ V(LoadKeyedFastElement) \ V(LoadKeyedGeneric) \ V(LoadKeyedSpecializedArrayElement) \ @@ -156,6 +157,7 @@ class LChunkBuilder; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ + V(StoreKeyedFastDoubleElement) \ V(StoreKeyedFastElement) \ V(StoreKeyedGeneric) \ V(StoreKeyedSpecializedArrayElement) \ @@ -588,9 +590,9 @@ class HValue: public ZoneObject { // 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 // 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 - // one input. They are phi and binary add. They always return NULL and - // expect the caller to take care of things. + // back. There are three operations that need to propagate back to more than + // one input. They are phi and binary div and mul. They always return NULL + // and expect the caller to take care of things. virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) { visited->Add(id()); return NULL; @@ -1123,40 +1125,19 @@ class HChange: public HUnaryOperation { class HClampToUint8: public HUnaryOperation { public: explicit HClampToUint8(HValue* value) - : HUnaryOperation(value), - input_rep_(Representation::None()) { - SetFlag(kFlexibleRepresentation); - set_representation(Representation::Tagged()); + : HUnaryOperation(value) { + set_representation(Representation::Integer32()); SetFlag(kUseGVN); } virtual Representation RequiredInputRepresentation(int index) const { - return input_rep_; - } - - 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(); - } + return Representation::None(); } DECLARE_CONCRETE_INSTRUCTION(ClampToUint8) protected: 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> { public: 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> { public: HStoreKeyedSpecializedArrayElement(HValue* external_elements, diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 887ba7360..7e62ec4c4 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -1666,8 +1666,8 @@ void HInferRepresentation::Analyze() { HValue* use = it.value(); if (use->IsPhi()) { int id = HPhi::cast(use)->phi_id(); - change = change || - connected_phis[i]->UnionIsChanged(*connected_phis[id]); + if (connected_phis[i]->UnionIsChanged(*connected_phis[id])) + change = true; } } } @@ -3901,7 +3901,9 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, bool is_store) { ASSERT(expr->IsMonomorphic()); 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) : BuildLoadKeyedGeneric(object, key); } @@ -3920,20 +3922,39 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, return BuildExternalArrayElementAccess(external_elements, checked_key, 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) { length = AddInstruction(new(zone()) HJSArrayLength(object)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); AddInstruction(elements); + if (is_store && !fast_double_elements) { + AddInstruction(new(zone()) HCheckMap( + elements, isolate()->factory()->fixed_array_map())); + } } else { AddInstruction(elements); + if (is_store && !fast_double_elements) { + AddInstruction(new(zone()) HCheckMap( + elements, isolate()->factory()->fixed_array_map())); + } length = AddInstruction(new(zone()) HFixedArrayLength(elements)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); } 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 { - 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; } } - // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt. - type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false; HBasicBlock* join = graph()->CreateBasicBlock(); @@ -4016,7 +4035,8 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, set_current_block(if_true); 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_fastobject = graph()->CreateBasicBlock(); HHasInstanceTypeAndBranch* typecheck = @@ -4032,12 +4052,28 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); elements = AddInstruction(new(zone()) HLoadElements(object)); elements->ClearFlag(HValue::kUseGVN); + bool fast_double_elements = + elements_kind == JSObject::FAST_DOUBLE_ELEMENTS; if (is_store) { - access = AddInstruction( - new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); + if (fast_double_elements) { + 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 { - access = AddInstruction( - new(zone()) HLoadKeyedFastElement(elements, checked_key)); + if (fast_double_elements) { + access = AddInstruction( + new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); + } else { + access = AddInstruction( + new(zone()) HLoadKeyedFastElement(elements, checked_key)); + } Push(access); } *has_side_effects |= access->HasSideEffects(); @@ -4049,14 +4085,30 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, set_current_block(if_fastobject); elements = AddInstruction(new(zone()) HLoadElements(object)); 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)); checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); if (is_store) { - access = AddInstruction( - new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); + if (fast_double_elements) { + access = AddInstruction( + new(zone()) HStoreKeyedFastDoubleElement(elements, + checked_key, + val)); + } else { + access = AddInstruction( + new(zone()) HStoreKeyedFastElement(elements, checked_key, val)); + } } else { - access = AddInstruction( - new(zone()) HLoadKeyedFastElement(elements, checked_key)); + if (fast_double_elements) { + access = AddInstruction( + new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key)); + } else { + access = AddInstruction( + new(zone()) HLoadKeyedFastElement(elements, checked_key)); + } } } else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) { if (is_store) { diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 48bd8b1a5..71aacf9a3 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -4158,6 +4158,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); Handle<Code> adaptor = masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); + __ SetCallKind(ecx, CALL_AS_METHOD); __ jmp(adaptor, RelocInfo::CODE_TARGET); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index 6293718f6..7211ba49a 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/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* key, - JSObject::ElementsKind elements_kind) { + JSObject::ElementsKind elements_kind, + uint32_t offset) { Register external_pointer_reg = ToRegister(external_pointer); int shift_size = ElementsKindToShiftSize(elements_kind); if (key->IsConstantOperand()) { @@ -2241,10 +2265,11 @@ Operand LCodeGen::BuildExternalArrayOperand( if (constant_value & 0xF0000000) { 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 { 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( LLoadKeyedSpecializedArrayElement* instr) { JSObject::ElementsKind elements_kind = instr->elements_kind(); - Operand operand(BuildExternalArrayOperand(instr->external_pointer(), - instr->key(), elements_kind)); + Operand operand(BuildFastArrayOperand(instr->external_pointer(), + instr->key(), elements_kind, 0)); if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { XMMRegister result(ToDoubleRegister(instr->result())); __ movss(result, operand); @@ -2790,7 +2815,8 @@ void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { __ ucomisd(input_reg, xmm0); __ j(above, &positive, 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)); __ jmp(&done, Label::kNear); __ bind(&zero); @@ -3000,8 +3026,8 @@ void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { void LCodeGen::DoStoreKeyedSpecializedArrayElement( LStoreKeyedSpecializedArrayElement* instr) { JSObject::ElementsKind elements_kind = instr->elements_kind(); - Operand operand(BuildExternalArrayOperand(instr->external_pointer(), - instr->key(), elements_kind)); + Operand operand(BuildFastArrayOperand(instr->external_pointer(), + instr->key(), elements_kind, 0)); if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value())); __ 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) { ASSERT(ToRegister(instr->context()).is(esi)); ASSERT(ToRegister(instr->object()).is(edx)); @@ -3451,7 +3499,8 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, DeoptimizeIf(not_equal, env); // 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)); __ jmp(&done, Label::kNear); diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index 7ab446dbf..c568bef5b 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -222,9 +222,10 @@ class LCodeGen BASE_EMBEDDED { Register ToRegister(int index) const; XMMRegister ToDoubleRegister(int index) const; int ToInteger32(LConstantOperand* op) const; - Operand BuildExternalArrayOperand(LOperand* external_pointer, - LOperand* key, - JSObject::ElementsKind elements_kind); + Operand BuildFastArrayOperand(LOperand* external_pointer, + LOperand* key, + JSObject::ElementsKind elements_kind, + uint32_t offset); // Specific math operations - used from DoUnaryMathOperation. void EmitIntegerMathAbs(LUnaryMathOperation* instr); diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index 1b9aeb58c..9951d2540 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/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) { object()->PrintTo(stream); 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( HLoadKeyedSpecializedArrayElement* instr) { 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( HStoreKeyedSpecializedArrayElement* instr) { Representation representation(instr->value()->representation()); diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index 0daab5f9d..6b60a6e40 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -116,6 +116,7 @@ class LCodeGen; V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ V(LoadKeyedFastElement) \ + V(LoadKeyedFastDoubleElement) \ V(LoadKeyedGeneric) \ V(LoadKeyedSpecializedArrayElement) \ V(LoadNamedField) \ @@ -141,6 +142,7 @@ class LCodeGen; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ + V(StoreKeyedFastDoubleElement) \ V(StoreKeyedFastElement) \ V(StoreKeyedGeneric) \ 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> { public: 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> { public: LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 136b24c98..3e037d79a 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -2044,6 +2044,9 @@ void MacroAssembler::AssertFastElements(Register elements) { Immediate(factory->fixed_array_map())); j(equal, &ok); cmp(FieldOperand(elements, HeapObject::kMapOffset), + Immediate(factory->fixed_double_array_map())); + j(equal, &ok); + cmp(FieldOperand(elements, HeapObject::kMapOffset), Immediate(factory->fixed_cow_array_map())); j(equal, &ok); Abort("JSObject with fast elements map has slow elements"); diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 266085088..9a690d76b 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/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, bool is_js_array) { // ----------- 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(¬_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, ¬_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 __ } } // namespace v8::internal diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index 45a39ffbc..bc47df8f2 100644 --- a/deps/v8/src/jsregexp.cc +++ b/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 // modification, are permitted provided that the following conditions are // met: @@ -1958,13 +1958,10 @@ void TextNode::GetQuickCheckDetails(QuickCheckDetails* details, ASSERT(characters_filled_in < details->characters()); int characters = details->characters(); int char_mask; - int char_shift; if (compiler->ascii()) { char_mask = String::kMaxAsciiCharCode; - char_shift = 8; } else { char_mask = String::kMaxUC16CharCode; - char_shift = 16; } for (int k = 0; k < elms_->length(); k++) { TextElement elm = elms_->at(k); @@ -4888,7 +4885,6 @@ void TextNode::CalculateOffsets() { cp_offset += elm.data.u_atom->data().length(); } else { 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); } - NodeInfo info = *node->info(); - // Create the correct assembler for the architecture. #ifndef V8_INTERPRETED_REGEXP // Native regexp implementation. diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index b9281070a..aaa98ed4a 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -195,7 +195,8 @@ function FormatMessage(message) { non_extensible_proto: ["%0", " is not extensible"], handler_non_object: ["Proxy.", "%0", " called with non-object as handler"], handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"], - handler_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_non_object_prop_names: ["Trap ", "%1", " returned non-object ", "%0"], 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; -DefineError(function Error() { }); -DefineError(function TypeError() { }); -DefineError(function RangeError() { }); -DefineError(function SyntaxError() { }); -DefineError(function ReferenceError() { }); -DefineError(function EvalError() { }); -DefineError(function URIError() { }); +// DefineError is a native function. Use explicit receiver. Otherwise +// the receiver will be 'undefined'. +this.DefineError(function Error() { }); +this.DefineError(function TypeError() { }); +this.DefineError(function RangeError() { }); +this.DefineError(function SyntaxError() { }); +this.DefineError(function ReferenceError() { }); +this.DefineError(function EvalError() { }); +this.DefineError(function URIError() { }); $Error.captureStackTrace = captureStackTrace; diff --git a/deps/v8/src/mips/assembler-mips.cc b/deps/v8/src/mips/assembler-mips.cc index 4ca6a91aa..51642e05c 100644 --- a/deps/v8/src/mips/assembler-mips.cc +++ b/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; 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. if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { - ASSERT(ast_id_for_reloc_info_ != kNoASTId); - RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_); - ast_id_for_reloc_info_ = kNoASTId; + RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId()); + ClearRecordedAstId(); reloc_info_writer.Write(&reloc_info_with_ast_id); } else { reloc_info_writer.Write(&rinfo); diff --git a/deps/v8/src/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h index f3730d6f3..a16cd80ea 100644 --- a/deps/v8/src/mips/assembler-mips.h +++ b/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 // 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. // 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 // member variable is a way to pass the information from the call site to // the relocation info. - unsigned ast_id_for_reloc_info_; + unsigned recorded_ast_id_; bool emit_debug_code() const { return emit_debug_code_; } diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc index d03443f27..d89d3e57c 100644 --- a/deps/v8/src/mips/code-stubs-mips.cc +++ b/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. __ mov(a2, zero_reg); __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION); + __ SetCallKind(t1, CALL_AS_METHOD); __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), RelocInfo::CODE_TARGET); } diff --git a/deps/v8/src/mips/macro-assembler-mips.cc b/deps/v8/src/mips/macro-assembler-mips.cc index 712ceec95..5e8d676ac 100644 --- a/deps/v8/src/mips/macro-assembler-mips.cc +++ b/deps/v8/src/mips/macro-assembler-mips.cc @@ -2080,8 +2080,7 @@ void MacroAssembler::Call(Handle<Code> code, bind(&start); ASSERT(RelocInfo::IsCodeTarget(rmode)); if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) { - ASSERT(ast_id_for_reloc_info_ == kNoASTId); - ast_id_for_reloc_info_ = ast_id; + SetRecordedAstId(ast_id); rmode = RelocInfo::CODE_TARGET_WITH_ID; } 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)); LoadRoot(at, Heap::kFixedArrayMapRootIndex); Branch(&ok, eq, elements, Operand(at)); + LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex); + Branch(&ok, eq, elements, Operand(at)); LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); Branch(&ok, eq, elements, Operand(at)); Abort("JSObject with fast elements map has slow elements"); diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index 919bdc40c..f1ffe9b63 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/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, bool is_js_array) { // ----------- 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 __ } } // namespace v8::internal diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js index 57de6c68f..bad08002d 100644 --- a/deps/v8/src/mirror-debugger.js +++ b/deps/v8/src/mirror-debugger.js @@ -1250,9 +1250,9 @@ const kFrameDetailsNameIndex = 0; const kFrameDetailsValueIndex = 1; const kFrameDetailsNameValueSize = 2; -const kFrameDetailsFlagDebuggerFrame = 1; -const kFrameDetailsFlagOptimizedFrame = 2; -const kFrameDetailsFlagInlinedFrame = 4; +const kFrameDetailsFlagDebuggerFrameMask = 1 << 0; +const kFrameDetailsFlagOptimizedFrameMask = 1 << 1; +const kFrameDetailsFlagInlinedFrameIndexMask = 7 << 2; /** * Wrapper for the frame details information retreived from the VM. The frame @@ -1266,7 +1266,7 @@ const kFrameDetailsFlagInlinedFrame = 4; * 5: Source position * 6: Construct call * 7: Is at return - * 8: Flags (debugger frame, optimized frame, inlined frame) + * 8: Flags (debugger frame, optimized frame, inlined frame index) * Arguments name, value * Locals name, value * Return value if any @@ -1312,22 +1312,27 @@ FrameDetails.prototype.isAtReturn = function() { FrameDetails.prototype.isDebuggerFrame = function() { %CheckExecutionState(this.break_id_); - var f = kFrameDetailsFlagDebuggerFrame; + var f = kFrameDetailsFlagDebuggerFrameMask; return (this.details_[kFrameDetailsFlagsIndex] & f) == f; } FrameDetails.prototype.isOptimizedFrame = function() { %CheckExecutionState(this.break_id_); - var f = kFrameDetailsFlagOptimizedFrame; + var f = kFrameDetailsFlagOptimizedFrameMask; return (this.details_[kFrameDetailsFlagsIndex] & f) == f; } FrameDetails.prototype.isInlinedFrame = function() { + return this.inlinedFrameIndex() > 0; +} + + +FrameDetails.prototype.inlinedFrameIndex = function() { %CheckExecutionState(this.break_id_); - var f = kFrameDetailsFlagInlinedFrame; - return (this.details_[kFrameDetailsFlagsIndex] & f) == f; + var f = kFrameDetailsFlagInlinedFrameIndexMask; + 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() { return this.details_.argumentCount(); }; @@ -1565,8 +1575,12 @@ FrameMirror.prototype.scope = function(index) { FrameMirror.prototype.evaluate = function(source, disable_break, opt_context_object) { - var result = %DebugEvaluate(this.break_id_, this.details_.frameId(), - source, Boolean(disable_break), opt_context_object); + var result = %DebugEvaluate(this.break_id_, + this.details_.frameId(), + this.details_.inlinedFrameIndex(), + source, + Boolean(disable_break), + opt_context_object); return MakeMirror(result); }; @@ -1591,8 +1605,10 @@ FrameMirror.prototype.invocationText = function() { // Try to find the function as a property in the receiver. Include the // prototype chain in the lookup. var property = GetUndefinedMirror(); - if (!receiver.isUndefined()) { - for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) { + if (receiver.isObject()) { + for (var r = receiver; + !r.isNull() && property.isUndefined(); + r = r.protoObject()) { property = r.lookupProperty(func); } } @@ -1719,6 +1735,7 @@ function ScopeDetails(frame, index) { this.break_id_ = frame.break_id_; this.details_ = %GetScopeDetails(frame.break_id_, frame.details_.frameId(), + frame.details_.inlinedFrameIndex(), index); } diff --git a/deps/v8/src/natives.h b/deps/v8/src/natives.h index a2831863a..5f34420d0 100644 --- a/deps/v8/src/natives.h +++ b/deps/v8/src/natives.h @@ -36,7 +36,7 @@ typedef bool (*NativeSourceCallback)(Vector<const char> name, int index); enum NativeType { - CORE, EXPERIMENTAL, D8 + CORE, EXPERIMENTAL, D8, TEST }; template <NativeType type> diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index 3d325b877..29632317a 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -315,7 +315,8 @@ void FixedDoubleArray::FixedDoubleArrayVerify() { if (!is_the_hole(i)) { double value = get(i); ASSERT(!isnan(value) || - BitCast<uint64_t>(value) == kCanonicalNonHoleNanInt64); + (BitCast<uint64_t>(value) == + BitCast<uint64_t>(canonical_not_the_hole_nan_as_double()))); } } } diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index eb537c75a..5726b3739 100644 --- a/deps/v8/src/objects-inl.h +++ b/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) { ASSERT(map() != HEAP->fixed_cow_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, padding, Object, kPaddingOffset) Address Foreign::address() { @@ -3989,7 +4007,8 @@ bool JSObject::HasIndexedInterceptor() { bool JSObject::AllowsSetElementsLength() { - bool result = elements()->IsFixedArray(); + bool result = elements()->IsFixedArray() || + elements()->IsFixedDoubleArray(); ASSERT(result == !HasExternalArrayElements()); 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) { return GetPropertyAttributeWithReceiver(this, key); } diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index ca780dbe0..341f92975 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -58,11 +58,6 @@ namespace internal { const int kGetterIndex = 0; 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, Object* value) { Object* result; @@ -194,7 +189,7 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver, AccessorInfo* data = AccessorInfo::cast(structure); Object* fun_obj = data->getter(); v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); - HandleScope scope; + HandleScope scope(isolate); JSObject* self = JSObject::cast(receiver); JSObject* holder_handle = JSObject::cast(holder); Handle<String> key(name); @@ -234,7 +229,7 @@ MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw, String* name_raw, Object* handler_raw) { Isolate* isolate = name_raw->GetIsolate(); - HandleScope scope; + HandleScope scope(isolate); Handle<Object> receiver(receiver_raw); Handle<Object> name(name_raw); Handle<Object> handler(handler_raw); @@ -2178,9 +2173,9 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck( } } - HandleScope scope; - Handle<Object> value_handle(value); Heap* heap = GetHeap(); + HandleScope scope(heap->isolate()); + Handle<Object> value_handle(value); heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); 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( String* name_raw, Object* value_raw, PropertyAttributes attributes, StrictModeFlag strict_mode) { Isolate* isolate = GetIsolate(); - HandleScope scope; + HandleScope scope(isolate); Handle<Object> receiver(this); Handle<Object> name(name_raw); Handle<Object> value(value_raw); @@ -2225,11 +2245,48 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( receiver.location(), name.location(), value.location() }; 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 = Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_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, bool* has_exception) { Isolate* isolate = GetIsolate(); - HandleScope scope; + HandleScope scope(isolate); Handle<JSReceiver> receiver(receiver_raw); Handle<Object> name(name_raw); 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, String* name, Object* value, @@ -2327,7 +2396,7 @@ MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, } if (result->IsReadOnly() && result->IsProperty()) { if (strict_mode == kStrictMode) { - HandleScope scope; + HandleScope scope(heap->isolate()); Handle<String> key(name); Handle<Object> holder(this); Handle<Object> args[2] = { key, holder }; @@ -2811,16 +2880,18 @@ MaybeObject* JSObject::NormalizeElements() { ASSERT(!HasExternalArrayElements()); // Find the backing store. - FixedArray* array = FixedArray::cast(elements()); + FixedArrayBase* array = FixedArrayBase::cast(elements()); Map* old_map = array->map(); bool is_arguments = (old_map == old_map->heap()->non_strict_arguments_elements_map()); if (is_arguments) { - array = FixedArray::cast(array->get(1)); + array = FixedArrayBase::cast(FixedArray::cast(array)->get(1)); } if (array->IsDictionary()) return array; - ASSERT(HasFastElements() || HasFastArgumentsElements()); + ASSERT(HasFastElements() || + HasFastDoubleElements() || + HasFastArgumentsElements()); // Compute the effective length and allocate a new backing store. int length = IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value() @@ -2833,7 +2904,7 @@ MaybeObject* JSObject::NormalizeElements() { } // 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++) { Object* value = NULL; if (has_double_elements) { @@ -2851,7 +2922,7 @@ MaybeObject* JSObject::NormalizeElements() { } } else { ASSERT(old_map->has_fast_elements()); - value = array->get(i); + value = FixedArray::cast(array)->get(i); } PropertyDetails details = PropertyDetails(NONE, NORMAL); if (!value->IsTheHole()) { @@ -3135,7 +3206,7 @@ MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { case FAST_DOUBLE_ELEMENTS: { int length = IsJSArray() ? Smi::cast(JSArray::cast(this)->length())->value() - : FixedArray::cast(elements())->length(); + : FixedDoubleArray::cast(elements())->length(); if (index < static_cast<uint32_t>(length)) { 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) { Isolate* isolate = GetIsolate(); // ECMA-262, 3rd, 8.6.2.5 @@ -7317,22 +7397,28 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, new_map = Map::cast(object); } - AssertNoAllocation no_gc; - WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); 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); set_map(new_map); set_elements(new_elements); break; - case DICTIONARY_ELEMENTS: + } + case DICTIONARY_ELEMENTS: { + AssertNoAllocation no_gc; + WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); CopySlowElementsToFast(NumberDictionary::cast(elements()), new_elements, mode); set_map(new_map); set_elements(new_elements); break; + } 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 // arguments are copied to the new backing store. FixedArray* parameter_map = FixedArray::cast(elements()); @@ -7368,6 +7454,8 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, new_elements->set(i, obj, UPDATE_WRITE_BARRIER); } } + set_map(new_map); + set_elements(new_elements); break; } case EXTERNAL_BYTE_ELEMENTS: @@ -7430,7 +7518,9 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( break; } + ASSERT(new_map->has_fast_double_elements()); set_map(new_map); + ASSERT(elems->IsFixedDoubleArray()); set_elements(elems); if (IsJSArray()) { @@ -7520,7 +7610,7 @@ void JSArray::Expand(int required_size) { static Failure* ArrayLengthRangeError(Heap* heap) { - HandleScope scope; + HandleScope scope(heap->isolate()); return heap->isolate()->Throw( *FACTORY->NewRangeError("invalid_array_length", HandleVector<Object>(NULL, 0))); @@ -7536,32 +7626,57 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { const int value = Smi::cast(smi_length)->value(); if (value < 0) return ArrayLengthRangeError(GetHeap()); - switch (GetElementsKind()) { - case FAST_ELEMENTS: { - int old_capacity = FixedArray::cast(elements())->length(); + JSObject::ElementsKind elements_kind = GetElementsKind(); + switch (elements_kind) { + case FAST_ELEMENTS: + case FAST_DOUBLE_ELEMENTS: { + int old_capacity = FixedArrayBase::cast(elements())->length(); if (value <= old_capacity) { if (IsJSArray()) { Object* obj; - { MaybeObject* maybe_obj = EnsureWritableFastElements(); + if (elements_kind == FAST_ELEMENTS) { + MaybeObject* maybe_obj = EnsureWritableFastElements(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } - FixedArray* fast_elements = FixedArray::cast(elements()); if (2 * value <= old_capacity) { // If more than half the elements won't be used, trim the array. if (value == 0) { initialize_elements(); } else { - fast_elements->set_length(value); - Address filler_start = fast_elements->address() + - FixedArray::OffsetOfElementAt(value); - int filler_size = (old_capacity - value) * kPointerSize; + Address filler_start; + int filler_size; + if (GetElementsKind() == FAST_ELEMENTS) { + 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); } } else { // Otherwise, fill the unused tail with holes. int old_length = FastD2I(JSArray::cast(this)->length()->Number()); - for (int i = value; i < old_length; i++) { - fast_elements->set_the_hole(i); + if (GetElementsKind() == FAST_ELEMENTS) { + 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)); @@ -7572,8 +7687,14 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { int new_capacity = value > min ? value : min; if (new_capacity <= kMaxFastElementsLength || !ShouldConvertToSlowElements(new_capacity)) { - MaybeObject* result = - SetFastElementsCapacityAndLength(new_capacity, value); + MaybeObject* result; + 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; return this; } @@ -7609,7 +7730,6 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { case EXTERNAL_FLOAT_ELEMENTS: case EXTERNAL_DOUBLE_ELEMENTS: case EXTERNAL_PIXEL_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: UNREACHABLE(); break; } @@ -7718,7 +7838,7 @@ MaybeObject* JSReceiver::SetPrototype(Object* value, // or [[Extensible]] must not violate the invariants defined in the preceding // paragraph. if (!this->map()->is_extensible()) { - HandleScope scope; + HandleScope scope(heap->isolate()); Handle<Object> handle(this, heap->isolate()); return heap->isolate()->Throw( *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()) { if (JSObject::cast(pt) == this) { // Cycle detected. - HandleScope scope; + HandleScope scope(heap->isolate()); return heap->isolate()->Throw( *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; 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: { ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); if (index < static_cast<uint32_t>(pixels->length())) { @@ -8043,9 +8172,6 @@ bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) { } break; } - case FAST_DOUBLE_ELEMENTS: - UNREACHABLE(); - break; case DICTIONARY_ELEMENTS: { if (element_dictionary()->FindEntry(index) != NumberDictionary::kNotFound) { @@ -8407,8 +8533,9 @@ MaybeObject* JSObject::SetDictionaryElement(uint32_t index, } else { new_length = dictionary->max_number_key() + 1; } - MaybeObject* result = - SetFastElementsCapacityAndLength(new_length, new_length); + MaybeObject* result = ShouldConvertToFastDoubleElements() + ? SetFastDoubleElementsCapacityAndLength(new_length, new_length) + : SetFastElementsCapacityAndLength(new_length, new_length); if (result->IsFailure()) return result; #ifdef DEBUG if (FLAG_trace_normalization) { @@ -8495,6 +8622,9 @@ MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( } // Otherwise default to slow case. + ASSERT(HasFastDoubleElements()); + ASSERT(map()->has_fast_double_elements()); + ASSERT(elements()->IsFixedDoubleArray()); Object* obj; { MaybeObject* maybe_obj = NormalizeElements(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; @@ -8512,7 +8642,7 @@ MaybeObject* JSObject::SetElement(uint32_t index, if (IsAccessCheckNeeded()) { Heap* heap = GetHeap(); if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { - HandleScope scope; + HandleScope scope(heap->isolate()); Handle<Object> value_handle(value); heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); return *value_handle; @@ -8948,10 +9078,13 @@ bool JSObject::HasDenseElements() { int capacity = 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()) { 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()) { NumberDictionary* dictionary = NumberDictionary::cast(backing_store); capacity = dictionary->Capacity(); @@ -8960,13 +9093,15 @@ bool JSObject::HasDenseElements() { } // Fall through. case FAST_ELEMENTS: + backing_store = FixedArray::cast(backing_store_base); capacity = backing_store->length(); for (int i = 0; i < capacity; ++i) { if (!backing_store->get(i)->IsTheHole()) ++number_of_elements; } break; case DICTIONARY_ELEMENTS: { - NumberDictionary* dictionary = NumberDictionary::cast(backing_store); + NumberDictionary* dictionary = + NumberDictionary::cast(FixedArray::cast(elements())); capacity = dictionary->Capacity(); number_of_elements = dictionary->NumberOfElements(); break; @@ -9474,6 +9609,21 @@ int JSObject::GetLocalElementKeys(FixedArray* storage, ASSERT(!storage || storage->length() >= counter); 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: { int length = ExternalPixelArray::cast(elements())->length(); while (counter < length) { @@ -9503,9 +9653,6 @@ int JSObject::GetLocalElementKeys(FixedArray* storage, ASSERT(!storage || storage->length() >= counter); break; } - case FAST_DOUBLE_ELEMENTS: - UNREACHABLE(); - break; case DICTIONARY_ELEMENTS: { if (storage != NULL) { element_dictionary()->CopyKeysTo(storage, @@ -11053,11 +11200,11 @@ void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { template<typename Shape, typename Key> Object* Dictionary<Shape, Key>::DeleteProperty(int entry, - JSObject::DeleteMode mode) { + JSReceiver::DeleteMode mode) { Heap* heap = Dictionary<Shape, Key>::GetHeap(); PropertyDetails details = DetailsAt(entry); // Ignore attributes if forcing a deletion. - if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { + if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) { return heap->false_value(); } SetEntry(entry, heap->null_value(), heap->null_value()); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 9765fe2a0..9b55ea747 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -1359,6 +1359,12 @@ class HeapNumber: public HeapObject { // JSObject and JSProxy. class JSReceiver: public HeapObject { public: + enum DeleteMode { + NORMAL_DELETION, + STRICT_DELETION, + FORCE_DELETION + }; + // Casting. static inline JSReceiver* cast(Object* obj); @@ -1373,6 +1379,8 @@ class JSReceiver: public HeapObject { PropertyAttributes attributes, StrictModeFlag strict_mode); + MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode); + // Returns the class name ([[Class]] property in the specification). String* class_name(); @@ -1386,14 +1394,8 @@ class JSReceiver: public HeapObject { PropertyAttributes GetLocalPropertyAttribute(String* name); // Can cause a GC. - bool HasProperty(String* name) { - return GetPropertyAttribute(name) != ABSENT; - } - - // Can cause a GC. - bool HasLocalProperty(String* name) { - return GetLocalPropertyAttribute(name) != ABSENT; - } + inline bool HasProperty(String* name); + inline bool HasLocalProperty(String* name); // Return the object's prototype (might be Heap::null_value()). inline Object* GetPrototype(); @@ -1422,12 +1424,6 @@ class JSReceiver: public HeapObject { // caching. class JSObject: public JSReceiver { public: - enum DeleteMode { - NORMAL_DELETION, - STRICT_DELETION, - FORCE_DELETION - }; - enum ElementsKind { // The "fast" kind for tagged values. Must be first to make it possible // to efficiently check maps if they have fast elements. @@ -2173,23 +2169,12 @@ class FixedDoubleArray: public FixedArrayBase { return kHeaderSize + length * kDoubleSize; } - // The following can't be declared inline as const static - // because they're 64-bit. - 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); - } + // Code Generation support. + static int OffsetOfElementAt(int index) { return SizeFor(index); } - inline static double canonical_not_the_hole_nan_as_double() { - return BitCast<double, uint64_t>(kCanonicalNonHoleNanInt64); - } + inline static bool is_the_hole_nan(double value); + inline static double hole_nan_as_double(); + inline static double canonical_not_the_hole_nan_as_double(); // Casting. static inline FixedDoubleArray* cast(Object* obj); @@ -6487,20 +6472,32 @@ class JSProxy: public JSReceiver { // [handler]: The handler property. DECL_ACCESSORS(handler, Object) + // [padding]: The padding slot (unused, see below). + DECL_ACCESSORS(padding, Object) + // Casting. static inline JSProxy* cast(Object* obj); + bool HasPropertyWithHandler(String* name); + MUST_USE_RESULT MaybeObject* SetPropertyWithHandler( - String* name_raw, - Object* value_raw, + String* name, + Object* value, PropertyAttributes attributes, StrictModeFlag strict_mode); + MUST_USE_RESULT MaybeObject* DeletePropertyWithHandler( + String* name, + DeleteMode mode); + MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler( JSReceiver* receiver, - String* name_raw, + String* name, bool* has_exception); + // Turn this into an (empty) JSObject. + void Fix(); + // Dispatched behavior. #ifdef OBJECT_PRINT inline void JSProxyPrint() { @@ -6512,9 +6509,14 @@ class JSProxy: public JSReceiver { void JSProxyVerify(); #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 kSize = kHandlerOffset + kPointerSize; + static const int kPaddingOffset = kHandlerOffset + kPointerSize; + static const int kSize = kPaddingOffset + kPointerSize; + + STATIC_CHECK(kSize == JSObject::kHeaderSize); typedef FixedBodyDescriptor<kHandlerOffset, kHandlerOffset + kPointerSize, diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 3085ef86b..5704cb805 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -648,6 +648,7 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, } if (ok) { result = new(zone()) FunctionLiteral( + isolate(), no_name, top_scope_, body, @@ -718,7 +719,6 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, { // Parse the function literal. - Handle<String> no_name = isolate()->factory()->empty_symbol(); Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with()); if (!info->closure().is_null()) { 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 // fall-through. It is much easier just to wrap the entire // 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); TryStatement* statement = ParseTryStatement(CHECK_OK); if (statement) { @@ -1453,10 +1453,10 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { // introduced dynamically when we meet their declarations, whereas // other functions are setup when entering the surrounding scope. SharedFunctionInfoLiteral* lit = - new(zone()) SharedFunctionInfoLiteral(shared); + new(zone()) SharedFunctionInfoLiteral(isolate(), shared); VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK); 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) // // 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); Expect(Token::LBRACE, CHECK_OK); 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. // // 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 Handle<String> name; do { @@ -1676,7 +1676,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // Compute the arguments for the runtime call. ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3); // We have at least 1 parameter. - arguments->Add(new(zone()) Literal(name)); + arguments->Add(NewLiteral(name)); CallRuntime* initialize; if (is_const) { @@ -1689,9 +1689,10 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // the number of arguments (1 or 2). initialize = new(zone()) CallRuntime( - isolate()->factory()->InitializeConstGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeConstGlobal), - arguments); + isolate(), + isolate()->factory()->InitializeConstGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeConstGlobal), + arguments); } else { // Add strict mode. // 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). initialize = new(zone()) CallRuntime( - isolate()->factory()->InitializeVarGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeVarGlobal), - arguments); + isolate(), + isolate()->factory()->InitializeVarGlobal_symbol(), + Runtime::FunctionForId(Runtime::kInitializeVarGlobal), + arguments); } block->AddStatement(new(zone()) ExpressionStatement(initialize)); @@ -1739,7 +1741,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, VariableProxy* proxy = initialization_scope->NewUnresolved(name, in_with); Assignment* assignment = - new(zone()) Assignment(op, proxy, value, position); + new(zone()) Assignment(isolate(), op, proxy, value, position); if (block) { block->AddStatement(new(zone()) ExpressionStatement(assignment)); } @@ -1842,7 +1844,8 @@ IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) { } else { 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. // 1: Evaluate the with expression. // 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) { result->AddStatement(new(zone()) EnterWithContextStatement(obj)); // Create body block. - Block* body = new(zone()) Block(NULL, 1, false); + Block* body = new(zone()) Block(isolate(), NULL, 1, false); body->AddStatement(stat); // 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()); // Return a try-finally statement. @@ -2032,7 +2035,7 @@ CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { 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 :: // 'switch' '(' Expression ')' '{' CaseClause* '}' - SwitchStatement* statement = new(zone()) SwitchStatement(labels); + SwitchStatement* statement = new(zone()) SwitchStatement(isolate(), labels); Target target(&this->target_stack_, statement); Expect(Token::SWITCH, CHECK_OK); @@ -2077,7 +2080,8 @@ Statement* Parser::ParseThrowStatement(bool* ok) { Expression* exception = ParseExpression(true, 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. - 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()); // Create a try/finally statement. @@ -2164,7 +2168,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { new(zone()) TryFinallyStatement(inner_body, inner_finally); 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); } else { Expect(Token::LBRACE, CHECK_OK); @@ -2193,7 +2197,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { catch_variable, catch_block); 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); catch_block = NULL; // Clear to indicate it's been handled. } @@ -2224,7 +2228,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels, // DoStatement :: // 'do' Statement 'while' '(' Expression ')' ';' - DoWhileStatement* loop = new(zone()) DoWhileStatement(labels); + DoWhileStatement* loop = new(zone()) DoWhileStatement(isolate(), labels); Target target(&this->target_stack_, loop); Expect(Token::DO, CHECK_OK); @@ -2255,7 +2259,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { // WhileStatement :: // 'while' '(' Expression ')' Statement - WhileStatement* loop = new(zone()) WhileStatement(labels); + WhileStatement* loop = new(zone()) WhileStatement(isolate(), labels); Target target(&this->target_stack_, loop); Expect(Token::WHILE, CHECK_OK); @@ -2285,7 +2289,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { if (peek() == Token::IN && !name.is_null()) { 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); Expect(Token::IN, CHECK_OK); @@ -2294,7 +2298,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { Statement* body = ParseStatement(NULL, CHECK_OK); 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(loop); // 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(); expression = NewThrowReferenceError(type); } - ForInStatement* loop = new(zone()) ForInStatement(labels); + ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); @@ -2334,7 +2338,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { } // Standard 'for' loop - ForStatement* loop = new(zone()) ForStatement(labels); + ForStatement* loop = new(zone()) ForStatement(isolate(), labels); Target target(&this->target_stack_, loop); // Parsed initializer at this point. @@ -2370,7 +2374,8 @@ Expression* Parser::ParseExpression(bool accept_IN, bool* ok) { Expect(Token::COMMA, CHECK_OK); int position = scanner().location().beg_pos; 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; } @@ -2442,7 +2447,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { 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); int right_position = scanner().peek_location().beg_pos; Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - return new(zone()) Conditional(expression, left, right, - left_position, right_position); + return new(zone()) Conditional( + 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); if (cmp != op) { // 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 { // 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); Literal* x_literal = x->AsLiteral(); 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(); 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. bool condition = literal->ToBoolean()->IsTrue(); Handle<Object> result(isolate()->heap()->ToBoolean(!condition)); - return new(zone()) Literal(result); + return NewLiteral(result); } else if (literal->IsNumber()) { // Compute some expressions involving only number literals. 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)) { op = Next(); @@ -2659,7 +2664,8 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { } int position = scanner().location().beg_pos; - return new(zone()) CountOperation(op, + return new(zone()) CountOperation(isolate(), + op, true /* prefix */, expression, position); @@ -2695,7 +2701,8 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { Token::Value next = Next(); int position = scanner().location().beg_pos; expression = - new(zone()) CountOperation(next, + new(zone()) CountOperation(isolate(), + next, false /* postfix */, expression, position); @@ -2721,7 +2728,7 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::LBRACK); int pos = scanner().location().beg_pos; 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); break; } @@ -2759,7 +2766,10 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) { Consume(Token::PERIOD); int pos = scanner().location().beg_pos; 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); break; } @@ -2795,7 +2805,8 @@ Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) { if (!stack->is_empty()) { int last = stack->pop(); - result = new(zone()) CallNew(result, + result = new(zone()) CallNew(isolate(), + result, new(zone()) ZoneList<Expression*>(0), last); } @@ -2843,7 +2854,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::LBRACK); int pos = scanner().location().beg_pos; 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 (index->IsPropertyName()) { fni_->PushLiteralName(index->AsLiteral()->AsPropertyName()); @@ -2859,7 +2870,10 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, Consume(Token::PERIOD); int pos = scanner().location().beg_pos; 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); break; } @@ -2868,7 +2882,7 @@ Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, // Consume one of the new prefixes (already parsed). ZoneList<Expression*>* args = ParseArguments(CHECK_OK); int last = stack->pop(); - result = new CallNew(result, args, last); + result = new(zone()) CallNew(isolate(), result, args, last); break; } default: @@ -2952,23 +2966,26 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { switch (peek()) { case Token::THIS: { Consume(Token::THIS); - result = new(zone()) VariableProxy(top_scope_->receiver()); + result = new(zone()) VariableProxy(isolate(), top_scope_->receiver()); break; } case 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; case 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; case 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; case Token::IDENTIFIER: @@ -2994,7 +3011,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { case Token::STRING: { Consume(Token::STRING); Handle<String> symbol = GetSymbol(CHECK_OK); - result = new(zone()) Literal(symbol); + result = NewLiteral(symbol); if (fni_ != NULL) fni_->PushLiteralName(symbol); break; } @@ -3121,8 +3138,8 @@ Expression* Parser::ParseArrayLiteral(bool* ok) { literals->set_map(isolate()->heap()->fixed_cow_array_map()); } - return new(zone()) ArrayLiteral(literals, values, - literal_index, is_simple, depth); + return new(zone()) ArrayLiteral( + 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()); Expect(Token::LBRACE, CHECK_OK); - Scanner::Location loc = scanner().location(); while (peek() != Token::RBRACE) { 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 // called "get" or "set". - key = new(zone()) Literal(id); + key = NewLiteral(id); break; } case Token::STRING: { @@ -3479,7 +3495,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { key = NewNumberLiteral(index); break; } - key = new(zone()) Literal(string); + key = NewLiteral(string); break; } case Token::NUMBER: { @@ -3495,7 +3511,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { if (Token::IsKeyword(next)) { Consume(next); Handle<String> string = GetSymbol(CHECK_OK); - key = new(zone()) Literal(string); + key = NewLiteral(string); } else { // Unexpected token. Token::Value next = Next(); @@ -3548,13 +3564,14 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { &is_simple, &fast_elements, &depth); - return new(zone()) ObjectLiteral(constant_properties, - properties, - literal_index, - is_simple, - fast_elements, - depth, - has_function); + return new(zone()) ObjectLiteral(isolate(), + constant_properties, + properties, + literal_index, + is_simple, + fast_elements, + depth, + has_function); } @@ -3573,7 +3590,8 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { Handle<String> js_flags = NextLiteralString(TENURED); 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()); fproxy->BindTo(fvar); body->Add(new(zone()) ExpressionStatement( - new(zone()) Assignment(Token::INIT_CONST, fproxy, - new(zone()) ThisFunction(), - RelocInfo::kNoPosition))); + new(zone()) Assignment(isolate(), + Token::INIT_CONST, + fproxy, + new(zone()) ThisFunction(isolate()), + RelocInfo::kNoPosition))); } // 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 = - new(zone()) FunctionLiteral(name, + new(zone()) FunctionLiteral(isolate(), + name, scope, body, materialized_literal_count, @@ -3843,7 +3864,7 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) { } // 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() { - return new(zone()) Literal(isolate()->factory()->undefined_value()); + return NewLiteral(isolate()->factory()->undefined_value()); } 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) { - 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); ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2); - args->Add(new(zone()) Literal(type)); - args->Add(new(zone()) Literal(array)); - return new(zone()) Throw(new(zone()) CallRuntime(constructor, NULL, args), - scanner().location().beg_pos); + args->Add(NewLiteral(type)); + args->Add(NewLiteral(array)); + CallRuntime* call_constructor = new(zone()) CallRuntime(isolate(), + constructor, + NULL, + args); + return new(zone()) Throw(isolate(), + call_constructor, + scanner().location().beg_pos); } // ---------------------------------------------------------------------------- diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 9ce1026c9..13a360358 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -668,9 +668,12 @@ class Parser { Expression* NewCall(Expression* expression, ZoneList<Expression*>* arguments, 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. Literal* NewNumberLiteral(double value); diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index ab22a79cd..bc280ea0a 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -734,6 +734,7 @@ class LinuxMutex : public Mutex { ASSERT(result == 0); result = pthread_mutex_init(&mutex_, &attrs); ASSERT(result == 0); + USE(result); } virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); } diff --git a/deps/v8/src/platform-nullos.cc b/deps/v8/src/platform-nullos.cc index 08480ca80..8c2a8633d 100644 --- a/deps/v8/src/platform-nullos.cc +++ b/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) { UNIMPLEMENTED(); } diff --git a/deps/v8/src/platform-posix.cc b/deps/v8/src/platform-posix.cc index 5be305af9..deb4b7561 100644 --- a/deps/v8/src/platform-posix.cc +++ b/deps/v8/src/platform-posix.cc @@ -33,6 +33,7 @@ #include <errno.h> #include <time.h> +#include <sys/mman.h> #include <sys/socket.h> #include <sys/resource.h> #include <sys/time.h> @@ -43,6 +44,8 @@ #include <netinet/in.h> #include <netdb.h> +#undef MAP_TYPE + #if defined(ANDROID) #define LOG_TAG "v8" #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 diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc index 35b1a8ece..b23e25ec9 100644 --- a/deps/v8/src/platform-win32.cc +++ b/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) { ::Sleep(milliseconds); } diff --git a/deps/v8/src/platform.h b/deps/v8/src/platform.h index c7fe984c4..4d7f9cf77 100644 --- a/deps/v8/src/platform.h +++ b/deps/v8/src/platform.h @@ -206,6 +206,10 @@ class OS { size_t* allocated, bool is_executable); 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(). static size_t AllocateAlignment(); diff --git a/deps/v8/src/rewriter.cc b/deps/v8/src/rewriter.cc index 64d7b3684..e8ca5b9de 100644 --- a/deps/v8/src/rewriter.cc +++ b/deps/v8/src/rewriter.cc @@ -66,9 +66,13 @@ class Processor: public AstVisitor { Expression* SetResult(Expression* value) { result_assigned_ = true; - VariableProxy* result_proxy = new VariableProxy(result_); - return new Assignment(Token::ASSIGN, result_proxy, value, - RelocInfo::kNoPosition); + Zone* zone = isolate()->zone(); + VariableProxy* result_proxy = new(zone) VariableProxy(isolate(), result_); + return new(zone) Assignment(isolate(), + Token::ASSIGN, + result_proxy, + value, + RelocInfo::kNoPosition); } // Node visitors. @@ -229,8 +233,10 @@ bool Rewriter::Rewrite(CompilationInfo* info) { if (processor.HasStackOverflow()) return false; if (processor.result_assigned()) { - VariableProxy* result_proxy = new VariableProxy(result); - body->Add(new ReturnStatement(result_proxy)); + Isolate* isolate = info->isolate(); + Zone* zone = isolate->zone(); + VariableProxy* result_proxy = new(zone) VariableProxy(isolate, result); + body->Add(new(zone) ReturnStatement(result_proxy)); } } diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 56507aeb4..b4259c4a5 100644 --- a/deps/v8/src/runtime.cc +++ b/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) { NoHandleAllocation ha; ASSERT(args.length() == 1); @@ -3872,7 +3880,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { || result.type() == CONSTANT_FUNCTION)) { Object* ok; { MaybeObject* maybe_ok = - obj->DeleteProperty(name, JSObject::NORMAL_DELETION); + obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION); if (!maybe_ok->ToObject(&ok)) return maybe_ok; } } @@ -4126,24 +4134,25 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, - Handle<JSObject> js_object, + Handle<JSReceiver> receiver, Handle<Object> key) { HandleScope scope(isolate); // Check if the given key is an array index. uint32_t index; - if (key->ToArrayIndex(&index)) { + if (receiver->IsJSObject() && key->ToArrayIndex(&index)) { // In Firefox/SpiderMonkey, Safari and Opera you can access the // characters of a string using [] notation. In the case of a // String object we just need to redirect the deletion to the // underlying string if the index is in range. Since the // underlying string does nothing with the deletion, we can ignore // such deletions. - if (js_object->IsStringObjectWithCharacterAt(index)) { + if (receiver->IsStringObjectWithCharacterAt(index)) { 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; @@ -4158,7 +4167,7 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, } 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; ASSERT(args.length() == 3); - CONVERT_CHECKED(JSObject, object, args[0]); + CONVERT_CHECKED(JSReceiver, object, args[0]); CONVERT_CHECKED(String, key, args[1]); CONVERT_SMI_ARG_CHECKED(strict, 2); return object->DeleteProperty(key, (strict == kStrictMode) - ? JSObject::STRICT_DELETION - : JSObject::NORMAL_DELETION); + ? JSReceiver::STRICT_DELETION + : JSReceiver::NORMAL_DELETION); } @@ -4306,11 +4315,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) { NoHandleAllocation na; ASSERT(args.length() == 2); - // Only JS objects can have properties. - if (args[0]->IsJSObject()) { - JSObject* object = JSObject::cast(args[0]); + // Only JS receivers can have properties. + if (args[0]->IsJSReceiver()) { + JSReceiver* receiver = JSReceiver::cast(args[0]); 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(); } @@ -8198,9 +8207,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { // index is non-negative. Handle<JSObject> object = Handle<JSObject>::cast(holder); if (index >= 0) { - return object->DeleteElement(index, JSObject::NORMAL_DELETION); + return object->DeleteElement(index, JSReceiver::NORMAL_DELETION); } 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 kFrameDetailsReceiverIndex = 1; static const int kFrameDetailsFunctionIndex = 2; @@ -10024,8 +10098,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { return heap->undefined_value(); } - int deoptimized_frame_index = -1; // Frame index in optimized frame. - DeoptimizedFrameInfo* deoptimized_frame = NULL; + int inlined_frame_index = 0; // Inlined frame index in optimized frame. int count = 0; JavaScriptFrameIterator it(isolate, id); @@ -10036,13 +10109,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { if (it.done()) return heap->undefined_value(); if (it.frame()->is_optimized()) { - deoptimized_frame_index = + inlined_frame_index = 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 // selected frame. @@ -10061,12 +10131,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { // Check for constructor frame. Inlined frames cannot be construct calls. 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(); // Get scope info and read from it for local variable information. 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()); ScopeInfo<> info(*scope_info); @@ -10083,14 +10154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { for (; i < info.number_of_stack_slots(); ++i) { // Use the value from the stack. locals->set(i * 2, *info.LocalName(i)); - if (it.frame()->is_optimized()) { - // 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)); - } + locals->set(i * 2 + 1, frame_inspector.GetExpression(i)); } if (i < info.NumberOfLocals()) { // 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 // of arguments matching the functions parameters. The rest of the // 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 // parameters for the function and fill more if more parameters are provided. 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()) { - ASSERT_EQ(argument_count, deoptimized_frame->parameters_count()); - } else { - if (argument_count < it.frame()->ComputeParametersCount()) { - argument_count = it.frame()->ComputeParametersCount(); - } + ASSERT_EQ(argument_count, frame_inspector.GetParametersCount()); } +#endif // Calculate the size of the result. int details_size = kFrameDetailsFirstDynamicIndex + @@ -10170,13 +10238,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { details->set(kFrameDetailsFrameIdIndex, *frame_id); // Add the function (same as in function frame). - if (it.frame()->is_optimized()) { - // 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()); - } + details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); // Add the arguments count. details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); @@ -10208,9 +10270,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { } if (it.frame()->is_optimized()) { flags |= 1 << 1; - if (deoptimized_frame_index > 0) { - flags |= 1 << 2; - } + flags |= inlined_frame_index << 2; } details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); @@ -10227,16 +10287,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { } // Parameter value. - if (it.frame()->is_optimized()) { - // Get the value from the deoptimized frame. - details->set(details_index++, deoptimized_frame->GetParameter(i)); + if (i < it.frame()->ComputeParametersCount()) { + // Get the value from the stack. + details->set(details_index++, frame_inspector.GetParameter(i)); } else { - if (i < it.frame()->ComputeParametersCount()) { - // Get the value from the stack. - details->set(details_index++, it.frame()->GetParameter(i)); - } else { - details->set(details_index++, heap->undefined_value()); - } + 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 // THE FRAME ITERATOR TO WRAP THE RECEIVER. Handle<Object> receiver(it.frame()->receiver(), isolate); - if (!receiver->IsJSObject()) { - // If the receiver is NOT a JSObject we have hit an optimization - // where a value object is not converted into a wrapped JS objects. - // To hide this optimization from the debugger, we wrap the receiver + if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) { + // If the receiver is not a JSObject and the function is not a + // builtin or strict-mode we have hit an optimization where a + // 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 // global context. it.Advance(); @@ -10268,12 +10324,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { } 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); return *isolate->factory()->NewJSArrayWithElements(details); } @@ -10309,12 +10359,15 @@ static bool CopyContextLocalsToScopeObject( // Create a plain JSObject which materializes the local scope for the specified // frame. -static Handle<JSObject> MaterializeLocalScope(Isolate* isolate, - JavaScriptFrame* frame) { +static Handle<JSObject> MaterializeLocalScope( + Isolate* isolate, + JavaScriptFrame* frame, + int inlined_frame_index) { Handle<JSFunction> function(JSFunction::cast(frame->function())); Handle<SharedFunctionInfo> shared(function->shared()); Handle<SerializedScopeInfo> serialized_scope_info(shared->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 // heap locals and extension properties of the debugged function. @@ -10327,7 +10380,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate, isolate, SetProperty(local_scope, scope_info.parameter_name(i), - Handle<Object>(frame->GetParameter(i), isolate), + Handle<Object>(frame_inspector.GetParameter(i)), NONE, kNonStrictMode), Handle<JSObject>()); @@ -10339,7 +10392,7 @@ static Handle<JSObject> MaterializeLocalScope(Isolate* isolate, isolate, SetProperty(local_scope, scope_info.stack_slot_name(i), - Handle<Object>(frame->GetExpression(i), isolate), + Handle<Object>(frame_inspector.GetExpression(i)), NONE, kNonStrictMode), Handle<JSObject>()); @@ -10459,9 +10512,12 @@ class ScopeIterator { ScopeTypeCatch }; - ScopeIterator(Isolate* isolate, JavaScriptFrame* frame) + ScopeIterator(Isolate* isolate, + JavaScriptFrame* frame, + int inlined_frame_index) : isolate_(isolate), frame_(frame), + inlined_frame_index_(inlined_frame_index), function_(JSFunction::cast(frame->function())), context_(Context::cast(frame->context())), local_done_(false), @@ -10546,7 +10602,7 @@ class ScopeIterator { return Handle<JSObject>(CurrentContext()->global()); case ScopeIterator::ScopeTypeLocal: // Materialize the content of the local scope into a JSObject. - return MaterializeLocalScope(isolate_, frame_); + return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_); case ScopeIterator::ScopeTypeWith: // Return the with object. return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); @@ -10626,6 +10682,7 @@ class ScopeIterator { private: Isolate* isolate_; JavaScriptFrame* frame_; + int inlined_frame_index_; Handle<JSFunction> function_; Handle<Context> context_; bool local_done_; @@ -10654,7 +10711,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) { // Count the visible scopes. int n = 0; - for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) { + for (ScopeIterator it(isolate, frame, 0); + !it.Done(); + it.Next()) { n++; } @@ -10669,14 +10728,15 @@ static const int kScopeDetailsSize = 2; // Return an array with scope details // args[0]: number: break id // 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: // 0: Scope type // 1: Scope object RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { HandleScope scope(isolate); - ASSERT(args.length() == 3); + ASSERT(args.length() == 4); // Check arguments. Object* check; @@ -10685,7 +10745,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { if (!maybe_check->ToObject(&check)) return maybe_check; } 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. StackFrame::Id id = UnwrapFrameId(wrapped_id); @@ -10694,7 +10755,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { // Find the requested scope. int n = 0; - ScopeIterator it(isolate, frame); + ScopeIterator it(isolate, frame, inlined_frame_index); for (; !it.Done() && n < index; it.Next()) { n++; } @@ -10724,7 +10785,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { // Print the scopes for the top frame. StackFrameLocator locator; 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(); } #endif @@ -11117,6 +11180,7 @@ static Handle<Context> CopyWithContextChain(Isolate* isolate, // Runtime_DebugEvaluate. static Handle<Object> GetArgumentsObject(Isolate* isolate, JavaScriptFrame* frame, + int inlined_frame_index, Handle<JSFunction> function, Handle<SerializedScopeInfo> scope_info, const ScopeInfo<>* sinfo, @@ -11128,6 +11192,7 @@ static Handle<Object> GetArgumentsObject(Isolate* isolate, if (sinfo->number_of_stack_slots() > 0) { index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol()); if (index != -1) { + CHECK(false); 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 = isolate->factory()->NewArgumentsObject(function, length); Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); @@ -11148,7 +11215,7 @@ static Handle<Object> GetArgumentsObject(Isolate* isolate, AssertNoAllocation no_gc; WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 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); return arguments; @@ -11175,7 +11242,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { // Check the execution state and decode arguments frame and source to be // evaluated. - ASSERT(args.length() == 5); + ASSERT(args.length() == 6); Object* check_result; { MaybeObject* maybe_check_result = Runtime_CheckExecutionState( RUNTIME_ARGUMENTS(isolate, args)); @@ -11184,9 +11251,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { } } CONVERT_CHECKED(Smi, wrapped_id, args[1]); - CONVERT_ARG_CHECKED(String, source, 2); - CONVERT_BOOLEAN_CHECKED(disable_break, args[3]); - Handle<Object> additional_context(args[4]); + CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]); + CONVERT_ARG_CHECKED(String, source, 3); + CONVERT_BOOLEAN_CHECKED(disable_break, args[4]); + Handle<Object> additional_context(args[5]); // Handle the processing of break. DisableBreak disable_break_save(disable_break); @@ -11226,7 +11294,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { #endif // 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); // Allocate a new context for the debug evaluation and set the extension @@ -11275,7 +11344,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { &has_pending_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, &sinfo, function_context); @@ -12214,8 +12284,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { // 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 // yet. -static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller, - bool* seen_caller) { +static bool ShowFrameInStackTrace(StackFrame* raw_frame, + Object* caller, + bool* seen_caller) { // Only display JS frames. if (!raw_frame->is_java_script()) return false; @@ -12228,11 +12299,25 @@ static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller, *seen_caller = true; return false; } - // Skip all frames until we've seen the caller. Also, skip the most - // obvious builtin calls. 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. - return *seen_caller && !frame->receiver()->IsJSBuiltinsObject(); + // Skip all frames until we've seen the caller. + if (!(*seen_caller)) return false; + // Also, skip the most obvious builtin calls. We recognize builtins + // as (1) functions called with the builtins object as the receiver and + // 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; } diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index e59c82cd6..ac912d812 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -284,6 +284,7 @@ namespace internal { F(CreateJSProxy, 2, 1) \ F(IsJSProxy, 1, 1) \ F(GetHandler, 1, 1) \ + F(Fix, 1, 1) \ \ /* Statements */ \ F(NewClosure, 3, 1) \ @@ -372,7 +373,7 @@ namespace internal { F(GetFrameCount, 1, 1) \ F(GetFrameDetails, 2, 1) \ F(GetScopeCount, 2, 1) \ - F(GetScopeDetails, 3, 1) \ + F(GetScopeDetails, 4, 1) \ F(DebugPrintScopes, 0, 1) \ F(GetThreadCount, 1, 1) \ F(GetThreadDetails, 2, 1) \ @@ -385,7 +386,7 @@ namespace internal { F(IsBreakOnException, 1, 1) \ F(PrepareStep, 3, 1) \ F(ClearStepping, 0, 1) \ - F(DebugEvaluate, 5, 1) \ + F(DebugEvaluate, 6, 1) \ F(DebugEvaluateGlobal, 4, 1) \ F(DebugGetLoadedScripts, 0, 1) \ F(DebugReferencedBy, 3, 1) \ @@ -636,7 +637,7 @@ class Runtime : public AllStatic { MUST_USE_RESULT static MaybeObject* ForceDeleteObjectProperty( Isolate* isolate, - Handle<JSObject> object, + Handle<JSReceiver> object, Handle<Object> key); MUST_USE_RESULT static MaybeObject* GetObjectProperty( diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js index 77b97aed8..4b600df73 100644 --- a/deps/v8/src/runtime.js +++ b/deps/v8/src/runtime.js @@ -354,7 +354,8 @@ function IN(x) { if (!IS_SPEC_OBJECT(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)); } diff --git a/deps/v8/src/scopes.cc b/deps/v8/src/scopes.cc index c6e2a4650..390a0b6e1 100644 --- a/deps/v8/src/scopes.cc +++ b/deps/v8/src/scopes.cc @@ -116,25 +116,27 @@ Variable* VariableMap::Lookup(Handle<String> name) { // Dummy constructor Scope::Scope(Type type) - : inner_scopes_(0), - variables_(false), - temps_(0), - params_(0), - unresolved_(0), - decls_(0), - already_resolved_(false) { + : isolate_(Isolate::Current()), + inner_scopes_(0), + variables_(false), + temps_(0), + params_(0), + unresolved_(0), + decls_(0), + already_resolved_(false) { SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null()); } Scope::Scope(Scope* outer_scope, Type type) - : inner_scopes_(4), - variables_(), - temps_(4), - params_(4), - unresolved_(16), - decls_(4), - already_resolved_(false) { + : isolate_(Isolate::Current()), + inner_scopes_(4), + variables_(), + temps_(4), + params_(4), + unresolved_(16), + decls_(4), + already_resolved_(false) { SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null()); // At some point we might want to provide outer scopes to // 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) - : inner_scopes_(4), - variables_(), - temps_(4), - params_(4), - unresolved_(16), - decls_(4), - already_resolved_(true) { + : isolate_(Isolate::Current()), + inner_scopes_(4), + variables_(), + temps_(4), + params_(4), + unresolved_(16), + decls_(4), + already_resolved_(true) { ASSERT(!scope_info.is_null()); SetDefaults(FUNCTION_SCOPE, NULL, scope_info); 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) - : inner_scopes_(1), + : isolate_(Isolate::Current()), + inner_scopes_(1), variables_(), temps_(0), params_(0), @@ -186,7 +190,7 @@ void Scope::SetDefaults(Type type, Handle<SerializedScopeInfo> scope_info) { outer_scope_ = outer_scope; type_ = type; - scope_name_ = FACTORY->empty_symbol(); + scope_name_ = isolate_->factory()->empty_symbol(); dynamics_ = NULL; receiver_ = NULL; function_ = NULL; @@ -295,9 +299,12 @@ void Scope::Initialize(bool inside_with) { receiver_ = outer_scope()->receiver(); } else { Variable* var = - variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR, - false, Variable::THIS); - var->set_rewrite(new Slot(var, Slot::PARAMETER, -1)); + variables_.Declare(this, + isolate_->factory()->this_symbol(), + Variable::VAR, + false, + Variable::THIS); + var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1)); receiver_ = var; } @@ -305,8 +312,11 @@ void Scope::Initialize(bool inside_with) { // Declare 'arguments' variable which exists in all functions. // Note that it might never be accessed, in which case it won't be // allocated during variable allocation. - variables_.Declare(this, FACTORY->arguments_symbol(), Variable::VAR, - true, Variable::ARGUMENTS); + variables_.Declare(this, + 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 // 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. ASSERT(scope_info_->StackSlotIndex(*name) < 0); @@ -340,7 +350,7 @@ Variable* Scope::LocalLookup(Handle<String> name) { Variable* var = 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; } @@ -397,7 +407,8 @@ VariableProxy* Scope::NewUnresolved(Handle<String> name, // the same name because they may be removed selectively via // RemoveUnresolved(). 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); return proxy; } @@ -697,7 +708,7 @@ Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) { // Declare a new non-local. var = map->Declare(NULL, name, mode, true, Variable::NORMAL); // Allocate it by giving it a dynamic lookup. - var->set_rewrite(new Slot(var, Slot::LOOKUP, -1)); + var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1)); } return var; } @@ -943,26 +954,28 @@ bool Scope::MustAllocateInContext(Variable* var) { bool Scope::HasArgumentsParameter() { 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 false; } 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) { - var->set_rewrite(new Slot(var, Slot::CONTEXT, num_heap_slots_++)); + var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++)); } void Scope::AllocateParameterLocals() { 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 bool uses_nonstrict_arguments = false; @@ -1009,7 +1022,7 @@ void Scope::AllocateParameterLocals() { } else { ASSERT(var->rewrite() == NULL || var->IsParameter()); 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) { ASSERT(var->scope() == this); ASSERT(var->rewrite() == NULL || - !var->IsVariable(FACTORY->result_symbol()) || + !var->IsVariable(isolate_->factory()->result_symbol()) || var->AsSlot() == NULL || var->AsSlot()->type() != Slot::LOCAL); if (var->rewrite() == NULL && MustAllocate(var)) { diff --git a/deps/v8/src/scopes.h b/deps/v8/src/scopes.h index a493d5752..e76fb5059 100644 --- a/deps/v8/src/scopes.h +++ b/deps/v8/src/scopes.h @@ -319,6 +319,8 @@ class Scope: public ZoneObject { explicit Scope(Type type); + Isolate* const isolate_; + // Scope tree. Scope* outer_scope_; // the immediately enclosing outer scope, or NULL 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. Scope(Scope* inner_scope, Handle<String> catch_variable_name); + inline Slot* NewSlot(Variable* var, Slot::Type type, int index) { + return new(isolate_->zone()) Slot(isolate_, var, type, index); + } + void AddInnerScope(Scope* inner_scope) { if (inner_scope != NULL) { inner_scopes_.Add(inner_scope); diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc index d41ce5589..0f80496b0 100644 --- a/deps/v8/src/spaces.cc +++ b/deps/v8/src/spaces.cc @@ -402,7 +402,9 @@ void MemoryAllocator::FreeRawMemory(void* mem, size_t length, Executability executable) { #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 if (isolate_->code_range()->contains(static_cast<Address>(mem))) { isolate_->code_range()->FreeRawMemory(mem, length); @@ -504,14 +506,28 @@ Page* MemoryAllocator::AllocatePages(int requested_pages, LOG(isolate_, NewEvent("PagedChunk", chunk, chunk_size)); *allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size); + // We may 'lose' a page due to alignment. 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)); 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(); 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())); ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner_identity()); 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); } c.init(NULL, 0, NULL); @@ -2672,9 +2689,10 @@ LargeObjectChunk* LargeObjectChunk::New(int size_in_bytes, Executability executable) { size_t requested = ChunkSizeFor(size_in_bytes); size_t size; + size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0; Isolate* isolate = Isolate::Current(); void* mem = isolate->memory_allocator()->AllocateRawMemory( - requested, &size, executable); + requested + guard_size, &size, executable); if (mem == NULL) return NULL; // 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); LOG(isolate, NewEvent("LargeObjectChunk", mem, size)); - if (size < requested) { + if (size < requested + guard_size) { isolate->memory_allocator()->FreeRawMemory( mem, size, executable); LOG(isolate, DeleteEvent("LargeObjectChunk", mem)); 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) ? kObjectSpaceCodeSpace : kObjectSpaceLoSpace; @@ -2742,9 +2766,11 @@ void LargeObjectSpace::TearDown() { ObjectSpace space = kObjectSpaceLoSpace; if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; size_t size = chunk->size(); - heap()->isolate()->memory_allocator()->FreeRawMemory(chunk->address(), - size, - executable); + size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0; + heap()->isolate()->memory_allocator()->FreeRawMemory( + chunk->address() - guard_size, + size + guard_size, + executable); heap()->isolate()->memory_allocator()->PerformAllocationCallback( space, kAllocationActionFree, size); } @@ -2941,10 +2967,15 @@ void LargeObjectSpace::FreeUnmarkedObjects() { objects_size_ -= object->Size(); page_count_--; ObjectSpace space = kObjectSpaceLoSpace; - if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace; - heap()->isolate()->memory_allocator()->FreeRawMemory(chunk_address, - chunk_size, - executable); + size_t guard_size = 0; + if (executable == EXECUTABLE) { + space = kObjectSpaceCodeSpace; + guard_size = Page::kPageSize; + } + heap()->isolate()->memory_allocator()->FreeRawMemory( + chunk_address - guard_size, + chunk_size + guard_size, + executable); heap()->isolate()->memory_allocator()->PerformAllocationCallback( space, kAllocationActionFree, size_); LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk_address)); diff --git a/deps/v8/src/spaces.h b/deps/v8/src/spaces.h index c554a3777..ac5d99872 100644 --- a/deps/v8/src/spaces.h +++ b/deps/v8/src/spaces.h @@ -647,13 +647,11 @@ class MemoryAllocator { #ifdef V8_TARGET_ARCH_X64 static const int kPagesPerChunk = 32; // 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 kChunkTableBitsPerLevel = 12; #else static const int kPagesPerChunk = 16; // 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 kChunkTableBitsPerLevel = 8; #endif @@ -662,7 +660,6 @@ class MemoryAllocator { MemoryAllocator(); static const int kChunkSize = kPagesPerChunk * Page::kPageSize; - static const int kChunkSizeLog2 = kPagesPerChunkLog2 + kPageSizeBits; // Maximum space size in bytes. intptr_t capacity_; diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index 93c50fa98..ffe4241ec 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -662,6 +662,8 @@ class KeyedLoadStubCompiler: public StubCompiler { static void GenerateLoadFastElement(MacroAssembler* masm); + static void GenerateLoadFastDoubleElement(MacroAssembler* masm); + static void GenerateLoadDictionaryElement(MacroAssembler* masm); private: @@ -717,6 +719,9 @@ class KeyedStoreStubCompiler: public StubCompiler { static void GenerateStoreFastElement(MacroAssembler* masm, bool is_js_array); + static void GenerateStoreFastDoubleElement(MacroAssembler* masm, + bool is_js_array); + static void GenerateStoreExternalArray(MacroAssembler* masm, JSObject::ElementsKind elements_kind); diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc index 11af057b1..36f835f00 100644 --- a/deps/v8/src/v8.cc +++ b/deps/v8/src/v8.cc @@ -50,6 +50,9 @@ bool V8::has_been_disposed_ = false; bool V8::has_fatal_error_ = false; bool V8::use_crankshaft_ = true; +static Mutex* entropy_mutex = OS::CreateMutex(); +static EntropySource entropy_source; + bool V8::Initialize(Deserializer* des) { InitializeOncePerProcess(); @@ -102,8 +105,14 @@ void V8::TearDown() { static void seed_random(uint32_t* state) { for (int i = 0; i < 2; ++i) { - state[i] = FLAG_random_seed; - while (state[i] == 0) { + if (FLAG_random_seed != 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(); } } @@ -124,6 +133,11 @@ static uint32_t random_base(uint32_t* state) { } +void V8::SetEntropySource(EntropySource source) { + entropy_source = source; +} + + // Used by JavaScript APIs uint32_t V8::Random(Isolate* isolate) { ASSERT(isolate == Isolate::Current()); diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h index e74a60c2f..e565ca5ae 100644 --- a/deps/v8/src/v8.h +++ b/deps/v8/src/v8.h @@ -91,6 +91,9 @@ class V8 : public AllStatic { static void FatalProcessOutOfMemory(const char* location, 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. static uint32_t Random(Isolate* isolate); // We use random numbers internally in memory allocation and in the diff --git a/deps/v8/src/v8globals.h b/deps/v8/src/v8globals.h index d86f299f4..aff27579f 100644 --- a/deps/v8/src/v8globals.h +++ b/deps/v8/src/v8globals.h @@ -506,6 +506,16 @@ enum CallKind { 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 #endif // V8_V8GLOBALS_H_ diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js index 53a03173b..984363586 100644 --- a/deps/v8/src/v8natives.js +++ b/deps/v8/src/v8natives.js @@ -663,7 +663,8 @@ function DefineProxyProperty(obj, p, attributes, should_throw) { var result = %_CallFunction(handler, p, attributes, defineProperty); if (!ToBoolean(result)) { if (should_throw) { - throw MakeTypeError("handler_failed", [handler, "defineProperty"]); + throw MakeTypeError("handler_returned_false", + [handler, "defineProperty"]); } else { return false; } @@ -1020,11 +1021,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. function ObjectSeal(obj) { if (!IS_SPEC_OBJECT(obj)) { throw MakeTypeError("obj_ctor_property_non_object", ["seal"]); } + if (%IsJSProxy(obj)) { + ProxyFix(obj); + } var names = ObjectGetOwnPropertyNames(obj); for (var i = 0; i < names.length; i++) { var name = names[i]; @@ -1034,7 +1054,8 @@ function ObjectSeal(obj) { DefineOwnProperty(obj, name, desc, true); } } - return ObjectPreventExtension(obj); + %PreventExtensions(obj); + return obj; } @@ -1043,6 +1064,9 @@ function ObjectFreeze(obj) { if (!IS_SPEC_OBJECT(obj)) { throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]); } + if (%IsJSProxy(obj)) { + ProxyFix(obj); + } var names = ObjectGetOwnPropertyNames(obj); for (var i = 0; i < names.length; i++) { var name = names[i]; @@ -1053,7 +1077,8 @@ function ObjectFreeze(obj) { DefineOwnProperty(obj, name, desc, true); } } - return ObjectPreventExtension(obj); + %PreventExtensions(obj); + return obj; } @@ -1062,6 +1087,9 @@ function ObjectPreventExtension(obj) { if (!IS_SPEC_OBJECT(obj)) { throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]); } + if (%IsJSProxy(obj)) { + ProxyFix(obj); + } %PreventExtensions(obj); return obj; } @@ -1072,6 +1100,9 @@ function ObjectIsSealed(obj) { if (!IS_SPEC_OBJECT(obj)) { throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]); } + if (%IsJSProxy(obj)) { + return false; + } var names = ObjectGetOwnPropertyNames(obj); for (var i = 0; i < names.length; i++) { var name = names[i]; @@ -1090,6 +1121,9 @@ function ObjectIsFrozen(obj) { if (!IS_SPEC_OBJECT(obj)) { throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]); } + if (%IsJSProxy(obj)) { + return false; + } var names = ObjectGetOwnPropertyNames(obj); for (var i = 0; i < names.length; i++) { var name = names[i]; @@ -1109,6 +1143,9 @@ function ObjectIsExtensible(obj) { if (!IS_SPEC_OBJECT(obj)) { throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]); } + if (%IsJSProxy(obj)) { + return true; + } return %IsExtensible(obj); } diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index ee5411d88..b8ae21879 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,8 +34,8 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 4 -#define BUILD_NUMBER 12 -#define PATCH_LEVEL 1 +#define BUILD_NUMBER 14 +#define PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h index 4c1290414..c23eb1689 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -125,7 +125,7 @@ struct Register { return names[index]; } - static Register toRegister(int code) { + static Register from_code(int code) { Register r = { code }; return r; } diff --git a/deps/v8/src/x64/code-stubs-x64.cc b/deps/v8/src/x64/code-stubs-x64.cc index 3cf7840d5..1a6efcbd6 100644 --- a/deps/v8/src/x64/code-stubs-x64.cc +++ b/deps/v8/src/x64/code-stubs-x64.cc @@ -2529,6 +2529,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { #else // Already there in AMD64 calling convention. ASSERT(arg1.is(rdi)); + USE(arg1); #endif // Locate the code entry and call it. @@ -3198,6 +3199,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); Handle<Code> adaptor = Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline(); + __ SetCallKind(rcx, CALL_AS_METHOD); __ Jump(adaptor, RelocInfo::CODE_TARGET); } diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc index 7eb08f7e0..2a31f28d5 100644 --- a/deps/v8/src/x64/deoptimizer-x64.cc +++ b/deps/v8/src/x64/deoptimizer-x64.cc @@ -128,7 +128,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { Address instruction_start = function->code()->instruction_start(); Address jump_table_address = instruction_start + function->code()->safepoint_table_offset(); +#ifdef DEBUG Address previous_pc = instruction_start; +#endif SafepointTableDeoptimiztionEntryIterator deoptimizations(function->code()); Address entry_pc = NULL; @@ -157,12 +159,16 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { CodePatcher patcher(call_address, Assembler::kCallInstructionLength); patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY), RelocInfo::NONE); +#ifdef DEBUG previous_pc = call_end_address; +#endif } else { // Not room enough for a long Call instruction. Write a short call // instruction to a long jump placed elsewhere in the code. +#ifdef DEBUG Address short_call_end_address = call_address + MacroAssembler::kShortCallInstructionLength; +#endif ASSERT(next_pc >= short_call_end_address); // Write jump in jump-table. @@ -177,7 +183,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { CodePatcher call_patcher(call_address, MacroAssembler::kShortCallInstructionLength); call_patcher.masm()->call(jump_table_address); +#ifdef DEBUG previous_pc = short_call_end_address; +#endif } // 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 // to restore all later. for (int i = 0; i < kNumberOfRegisters; i++) { - Register r = Register::toRegister(i); + Register r = Register::from_code(i); __ push(r); } @@ -801,12 +809,12 @@ void Deoptimizer::EntryGenerator::Generate() { // Restore the registers from the stack. 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 // and overwrite this afterwards. if (r.is(rsp)) { ASSERT(i > 0); - r = Register::toRegister(i - 1); + r = Register::from_code(i - 1); } __ pop(r); } diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index a54bff59b..0f7e5b3d7 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -4060,10 +4060,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { default: { VisitForAccumulatorValue(expr->right()); Condition cc = no_condition; - bool strict = false; switch (op) { case Token::EQ_STRICT: - strict = true; // Fall through. case Token::EQ: cc = equal; diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index 98667ce87..49361e4f3 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -1883,7 +1883,6 @@ void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, __ push(ToRegister(instr->InputAt(0))); __ Push(instr->function()); - Register temp = ToRegister(instr->TempAt(0)); static const int kAdditionalDelta = 10; int delta = 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* key, - JSObject::ElementsKind elements_kind) { + JSObject::ElementsKind elements_kind, + uint32_t offset) { Register external_pointer_reg = ToRegister(external_pointer); int shift_size = ElementsKindToShiftSize(elements_kind); if (key->IsConstantOperand()) { @@ -2256,10 +2280,12 @@ Operand LCodeGen::BuildExternalArrayOperand( if (constant_value & 0xF0000000) { 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 { 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( LLoadKeyedSpecializedArrayElement* instr) { JSObject::ElementsKind elements_kind = instr->elements_kind(); - Operand operand(BuildExternalArrayOperand(instr->external_pointer(), - instr->key(), elements_kind)); + Operand operand(BuildFastArrayOperand(instr->external_pointer(), + instr->key(), elements_kind, 0)); if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { XMMRegister result(ToDoubleRegister(instr->result())); __ movss(result, operand); @@ -2994,8 +3020,8 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { void LCodeGen::DoStoreKeyedSpecializedArrayElement( LStoreKeyedSpecializedArrayElement* instr) { JSObject::ElementsKind elements_kind = instr->elements_kind(); - Operand operand(BuildExternalArrayOperand(instr->external_pointer(), - instr->key(), elements_kind)); + Operand operand(BuildFastArrayOperand(instr->external_pointer(), + instr->key(), elements_kind, 0)); if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) { XMMRegister value(ToDoubleRegister(instr->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) { ASSERT(ToRegister(instr->object()).is(rdx)); ASSERT(ToRegister(instr->key()).is(rcx)); diff --git a/deps/v8/src/x64/lithium-codegen-x64.h b/deps/v8/src/x64/lithium-codegen-x64.h index feacc2c82..d7c72b544 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.h +++ b/deps/v8/src/x64/lithium-codegen-x64.h @@ -215,10 +215,11 @@ class LCodeGen BASE_EMBEDDED { Register ToRegister(int index) const; XMMRegister ToDoubleRegister(int index) const; - Operand BuildExternalArrayOperand( + Operand BuildFastArrayOperand( LOperand* external_pointer, LOperand* key, - JSObject::ElementsKind elements_kind); + JSObject::ElementsKind elements_kind, + uint32_t offset); // Specific math operations - used from DoUnaryMathOperation. void EmitIntegerMathAbs(LUnaryMathOperation* instr); diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc index b2994cd15..5b502a80c 100644 --- a/deps/v8/src/x64/lithium-x64.cc +++ b/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) { object()->PrintTo(stream); 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( HLoadKeyedSpecializedArrayElement* instr) { 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( HStoreKeyedSpecializedArrayElement* instr) { Representation representation(instr->value()->representation()); diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h index af0b29991..12bdfb28a 100644 --- a/deps/v8/src/x64/lithium-x64.h +++ b/deps/v8/src/x64/lithium-x64.h @@ -121,6 +121,7 @@ class LCodeGen; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ + V(LoadKeyedFastDoubleElement) \ V(LoadKeyedFastElement) \ V(LoadKeyedGeneric) \ V(LoadKeyedSpecializedArrayElement) \ @@ -147,6 +148,7 @@ class LCodeGen; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ + V(StoreKeyedFastDoubleElement) \ V(StoreKeyedFastElement) \ V(StoreKeyedGeneric) \ 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> { public: 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> { public: LStoreKeyedSpecializedArrayElement(LOperand* external_pointer, diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index 1df022843..2b15553f1 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -385,6 +385,9 @@ void MacroAssembler::AssertFastElements(Register elements) { Heap::kFixedArrayMapRootIndex); j(equal, &ok, Label::kNear); CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), + Heap::kFixedDoubleArrayMapRootIndex); + j(equal, &ok, Label::kNear); + CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), Heap::kFixedCOWArrayMapRootIndex); j(equal, &ok, Label::kNear); Abort("JSObject with fast elements map has slow elements"); diff --git a/deps/v8/src/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/x64/regexp-macro-assembler-x64.cc index 2ea17f0e9..395466e77 100644 --- a/deps/v8/src/x64/regexp-macro-assembler-x64.cc +++ b/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()); 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), current_character()); BranchOrBacktrack(zero, on_no_match); @@ -676,7 +675,6 @@ bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type, } __ movq(rbx, ExternalReference::re_word_character_map()); 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), current_character()); BranchOrBacktrack(not_zero, on_no_match); diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index 71ce85616..b8e5f22ed 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -1089,9 +1089,8 @@ void StubCompiler::GenerateLoadConstant(JSObject* object, __ JumpIfSmi(receiver, miss); // Check that the maps haven't changed. - Register reg = - CheckPrototypes(object, receiver, holder, - scratch1, scratch2, scratch3, name, miss); + CheckPrototypes(object, receiver, holder, + scratch1, scratch2, scratch3, name, miss); // Return the constant 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, bool is_js_array) { // ----------- 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(¬_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, ¬_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 __ } } // namespace v8::internal diff --git a/deps/v8/src/zone.h b/deps/v8/src/zone.h index af9c916d7..abb53ad46 100644 --- a/deps/v8/src/zone.h +++ b/deps/v8/src/zone.h @@ -74,6 +74,8 @@ class Zone { inline void adjust_segment_bytes_allocated(int delta); + inline Isolate* isolate() { return isolate_; } + static unsigned allocation_size_; private: diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript index 0ef5667ab..b0a71664c 100644 --- a/deps/v8/test/cctest/SConscript +++ b/deps/v8/test/cctest/SConscript @@ -29,9 +29,23 @@ import sys from os.path import join, dirname, abspath root_dir = dirname(File('SConstruct').rfile().abspath) sys.path.append(join(root_dir, 'tools')) +import js2c 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 = { 'all': [ 'gay-fixed.cc', @@ -109,9 +123,19 @@ def Build(): env = Environment(tools=tools) env.Replace(**context.flags['cctest']) 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 # PDB files when compiling using MSVC so we specify it manually. # This should not affect any other platforms. + object_files.append(js_files_obj) return env.Program('cctest', ['cctest.cc', cctest_files, object_files], PDB='cctest.exe.pdb') diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 0a74ce3ca..9cbcb9cfa 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -26,6 +26,9 @@ # 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' ], 'targets': [ { @@ -33,11 +36,13 @@ 'type': 'executable', 'dependencies': [ '../../tools/gyp/v8.gyp:v8', + 'resources', ], 'include_dirs': [ '../../src', ], 'sources': [ + '<(generated_file)', 'cctest.cc', 'gay-fixed.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)', + ], + } + ], + }, ], } diff --git a/deps/v8/test/cctest/log-eq-of-logging-and-traversal.js b/deps/v8/test/cctest/log-eq-of-logging-and-traversal.js index e661efe02..cd52da545 100644 --- a/deps/v8/test/cctest/log-eq-of-logging-and-traversal.js +++ b/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); } - 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 equal = true; // 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 // functions traversal may erroneously recognize them as functions, so we are // expecting more functions in traversal vs. logging. - while (i < k && j < l) { - var entryA = logging_entries[i], entryB = traversal_entries[j]; + while (l_pos < l_len && t_pos < t_len) { + var entryA = logging_entries[l_pos]; + var entryB = traversal_entries[t_pos]; var cmp = addressComparator(entryA, entryB); var entityA = entryA[1], entityB = entryB[1]; var address = entryA[0]; if (cmp < 0) { - ++i; + ++l_pos; entityB = null; } else if (cmp > 0) { - ++j; + ++t_pos; entityA = null; address = entryB[0]; } else { - ++i; - ++j; + ++l_pos; + ++t_pos; } var entities_equal = entitiesEqual(entityA, entityB); if (!entities_equal) equal = false; comparison.push([entities_equal, address, entityA, entityB]); } - if (i < k) equal = false; - while (i < k) { - var entryA = logging_entries[i++]; + if (l_pos < l_len) equal = false; + while (l_pos < l_len) { + var entryA = logging_entries[l_pos++]; comparison.push([false, entryA[0], entryA[1], null]); } return [equal, comparison]; diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 8d8770f13..bc9a0e2ca 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/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) { v8::HandleScope scope; LocalContext env; @@ -2048,10 +2132,15 @@ THREADED_TEST(GetSetProperty) { THREADED_TEST(PropertyAttributes) { v8::HandleScope scope; 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 - Local<String> prop = v8_str("read_only"); + prop = v8_str("read_only"); context->Global()->Set(prop, v8_num(7), v8::ReadOnly); CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); + CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop)); Script::Compile(v8_str("read_only = 9"))->Run(); CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); context->Global()->Set(prop, v8_num(10)); @@ -2062,6 +2151,25 @@ THREADED_TEST(PropertyAttributes) { CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); Script::Compile(v8_str("delete dont_delete"))->Run(); 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(); } diff --git a/deps/v8/test/cctest/test-ast.cc b/deps/v8/test/cctest/test-ast.cc index d1e537d9d..786a54a11 100644 --- a/deps/v8/test/cctest/test-ast.cc +++ b/deps/v8/test/cctest/test-ast.cc @@ -40,7 +40,7 @@ TEST(List) { CHECK_EQ(0, list->length()); ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT); - AstNode* node = new EmptyStatement(); + AstNode* node = new(ZONE) EmptyStatement(); list->Add(node); CHECK_EQ(1, list->length()); CHECK_EQ(node, list->at(0)); diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index 5704b07ac..262e7bb50 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -12,6 +12,7 @@ #include "v8.h" #include "log.h" #include "cpu-profiler.h" +#include "natives.h" #include "v8threads.h" #include "v8utils.h" #include "cctest.h" @@ -469,6 +470,8 @@ TEST(IsLoggingPreserved) { } +typedef i::NativesCollection<i::TEST> TestSources; + // Test that logging of code create / move / delete events // is equivalent to traversal of a resulting heap. TEST(EquivalenceOfLoggingAndTraversal) { @@ -505,38 +508,25 @@ TEST(EquivalenceOfLoggingAndTraversal) { v8::Handle<v8::String> log_str = v8::String::New(log.start(), log.length()); initialize_logger.env()->Global()->Set(v8_str("_log"), log_str); - const char* scripts[] = { - "tools/splaytree.js", "tools/codemap.js", "tools/csvparser.js", - "tools/consarray.js", "tools/profile.js", "tools/profile_view.js", - "tools/logreader.js", "test/cctest/log-eq-of-logging-and-traversal.js" - }; - int scripts_count = sizeof(scripts) / sizeof(scripts[0]); - v8::Handle<v8::Value> last_result; - for (int i = 0; i < scripts_count; ++i) { - bool exists = true; - i::Vector<const char> source(i::ReadFile(scripts[i], &exists, true)); - CHECK(exists); - CHECK_GT(source.length(), 0); - v8::Handle<v8::String> source_str = - v8::String::New(source.start(), source.length()); - v8::TryCatch try_catch; - v8::Handle<v8::Script> script = - v8::Script::Compile(source_str, v8_str(scripts[i])); - if (script.IsEmpty()) { - v8::String::Utf8Value exception(try_catch.Exception()); - printf("compile %s: %s\n", scripts[i], *exception); - CHECK(false); - } - last_result = script->Run(); - if (last_result.IsEmpty()) { - v8::String::Utf8Value exception(try_catch.Exception()); - printf("run %s: %s\n", scripts[i], *exception); - CHECK(false); - } + i::Vector<const unsigned char> source = TestSources::GetScriptsSource(); + v8::Handle<v8::String> source_str = v8::String::New( + reinterpret_cast<const char*>(source.start()), source.length()); + v8::TryCatch try_catch; + v8::Handle<v8::Script> script = v8::Script::Compile(source_str, v8_str("")); + if (script.IsEmpty()) { + v8::String::Utf8Value exception(try_catch.Exception()); + printf("compile: %s\n", *exception); + CHECK(false); + } + v8::Handle<v8::Value> result = script->Run(); + if (result.IsEmpty()) { + v8::String::Utf8Value exception(try_catch.Exception()); + printf("run: %s\n", *exception); + CHECK(false); } // The result either be a "true" literal or problem description. - if (!last_result->IsTrue()) { - v8::Local<v8::String> s = last_result->ToString(); + if (!result->IsTrue()) { + v8::Local<v8::String> s = result->ToString(); i::ScopedVector<char> data(s->Length() + 1); CHECK_NE(NULL, data.start()); s->WriteAscii(data.start()); diff --git a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js index 584d1afda..9ed1dbbed 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js +++ b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized-double.js @@ -44,21 +44,44 @@ function listener(event, exec_state, event_data, data) { for (var i = 0; i < exec_state.frameCount(); i++) { var frame = exec_state.frame(i); if (i < exec_state.frameCount() - 1) { - // All frames except the bottom one has normal variables a and b. + var expected_a = i * 2 + 1 + (i * 2 + 1) / 100; + var expected_b = i * 2 + 2 + (i * 2 + 2) / 100; + var expected_x = (i + 1) * 2 + 1 + ((i + 1) * 2 + 1) / 100; + var expected_y = (i + 1) * 2 + 2 + ((i + 1) * 2 + 2) / 100; + + // All frames except the bottom one has normal variables a and b. assertEquals('a', frame.localName(0)); assertEquals('b', frame.localName(1)); - assertEquals(i * 2 + 1 + (i * 2 + 1) / 100, - frame.localValue(0).value()); - assertEquals(i * 2 + 2 + (i * 2 + 2) / 100, - frame.localValue(1).value()); + assertEquals(expected_a, frame.localValue(0).value()); + assertEquals(expected_b, frame.localValue(1).value()); // All frames except the bottom one has arguments variables x and y. assertEquals('x', frame.argumentName(0)); assertEquals('y', frame.argumentName(1)); - assertEquals((i + 1) * 2 + 1 + ((i + 1) * 2 + 1) / 100, - frame.argumentValue(0).value()); - assertEquals((i + 1) * 2 + 2 + ((i + 1) * 2 + 2) / 100, - frame.argumentValue(1).value()); + assertEquals(expected_x, frame.argumentValue(0).value()); + assertEquals(expected_y, frame.argumentValue(1).value()); + + // All frames except the bottom one have two scopes. + assertEquals(2, frame.scopeCount()); + assertEquals(debug.ScopeType.Local, frame.scope(0).scopeType()); + assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType()); + assertEquals(expected_a, frame.scope(0).scopeObject().value()['a']); + assertEquals(expected_b, frame.scope(0).scopeObject().value()['b']); + assertEquals(expected_x, frame.scope(0).scopeObject().value()['x']); + assertEquals(expected_y, frame.scope(0).scopeObject().value()['y']); + + // Evaluate in the inlined frame. + assertEquals(expected_a, frame.evaluate('a').value()); + assertEquals(expected_x, frame.evaluate('x').value()); + assertEquals(expected_x, frame.evaluate('arguments[0]').value()); + assertEquals(expected_a + expected_b + expected_x + expected_y, + frame.evaluate('a + b + x + y').value()); + assertEquals(expected_x + expected_y, + frame.evaluate('arguments[0] + arguments[1]').value()); + } else { + // The bottom frame only have the global scope. + assertEquals(1, frame.scopeCount()); + assertEquals(debug.ScopeType.Global, frame.scope(0).scopeType()); } // Check the frame function. @@ -75,12 +98,13 @@ function listener(event, exec_state, event_data, data) { // Check for construct call. assertEquals(testingConstructCall && i == 4, frame.isConstructCall()); - // When function f is optimized (2 means YES, see runtime.cc) we + // When function f is optimized (1 means YES, see runtime.cc) we // expect an optimized frame for f with g1, g2 and g3 inlined. - if (%GetOptimizationStatus(f) == 2) { + if (%GetOptimizationStatus(f) == 1) { if (i == 1 || i == 2 || i == 3) { assertTrue(frame.isOptimizedFrame()); assertTrue(frame.isInlinedFrame()); + assertEquals(4 - i, frame.inlinedFrameIndex()); } else if (i == 4) { assertTrue(frame.isOptimizedFrame()); assertFalse(frame.isInlinedFrame()); diff --git a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js index 1aaf29633..683c139d8 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js +++ b/deps/v8/test/mjsunit/debug-evaluate-locals-optimized.js @@ -44,17 +44,44 @@ function listener(event, exec_state, event_data, data) { for (var i = 0; i < exec_state.frameCount(); i++) { var frame = exec_state.frame(i); if (i < exec_state.frameCount() - 1) { + var expected_a = i * 2 + 1; + var expected_b = i * 2 + 2; + var expected_x = (i + 1) * 2 + 1; + var expected_y = (i + 1) * 2 + 2; + // All frames except the bottom one has normal variables a and b. assertEquals('a', frame.localName(0)); assertEquals('b', frame.localName(1)); - assertEquals(i * 2 + 1, frame.localValue(0).value()); - assertEquals(i * 2 + 2, frame.localValue(1).value()); + assertEquals(expected_a, frame.localValue(0).value()); + assertEquals(expected_b, frame.localValue(1).value()); // All frames except the bottom one has arguments variables x and y. assertEquals('x', frame.argumentName(0)); assertEquals('y', frame.argumentName(1)); - assertEquals((i + 1) * 2 + 1, frame.argumentValue(0).value()); - assertEquals((i + 1) * 2 + 2, frame.argumentValue(1).value()); + assertEquals(expected_x, frame.argumentValue(0).value()); + assertEquals(expected_y, frame.argumentValue(1).value()); + + // All frames except the bottom one have two scopes. + assertEquals(2, frame.scopeCount()); + assertEquals(debug.ScopeType.Local, frame.scope(0).scopeType()); + assertEquals(debug.ScopeType.Global, frame.scope(1).scopeType()); + assertEquals(expected_a, frame.scope(0).scopeObject().value()['a']); + assertEquals(expected_b, frame.scope(0).scopeObject().value()['b']); + assertEquals(expected_x, frame.scope(0).scopeObject().value()['x']); + assertEquals(expected_y, frame.scope(0).scopeObject().value()['y']); + + // Evaluate in the inlined frame. + assertEquals(expected_a, frame.evaluate('a').value()); + assertEquals(expected_x, frame.evaluate('x').value()); + assertEquals(expected_x, frame.evaluate('arguments[0]').value()); + assertEquals(expected_a + expected_b + expected_x + expected_y, + frame.evaluate('a + b + x + y').value()); + assertEquals(expected_x + expected_y, + frame.evaluate('arguments[0] + arguments[1]').value()); + } else { + // The bottom frame only have the global scope. + assertEquals(1, frame.scopeCount()); + assertEquals(debug.ScopeType.Global, frame.scope(0).scopeType()); } // Check the frame function. @@ -71,12 +98,13 @@ function listener(event, exec_state, event_data, data) { // Check for construct call. assertEquals(testingConstructCall && i == 4, frame.isConstructCall()); - // When function f is optimized (2 means YES, see runtime.cc) we + // When function f is optimized (1 means YES, see runtime.cc) we // expect an optimized frame for f with g1, g2 and g3 inlined. - if (%GetOptimizationStatus(f) == 2) { + if (%GetOptimizationStatus(f) == 1) { if (i == 1 || i == 2 || i == 3) { assertTrue(frame.isOptimizedFrame()); assertTrue(frame.isInlinedFrame()); + assertEquals(4 - i, frame.inlinedFrameIndex()); } else if (i == 4) { assertTrue(frame.isOptimizedFrame()); assertFalse(frame.isInlinedFrame()); diff --git a/deps/v8/test/mjsunit/debug-receiver.js b/deps/v8/test/mjsunit/debug-receiver.js new file mode 100644 index 000000000..21cdde84a --- /dev/null +++ b/deps/v8/test/mjsunit/debug-receiver.js @@ -0,0 +1,126 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --expose-debug-as debug +// Get the Debug object exposed from the debug context global object. +Debug = debug.Debug; + +var test_name; +var listener_delegate; +var listener_called; +var exception; +var expected_receiver; +var begin_test_count = 0; +var end_test_count = 0; +var break_count = 0; + +// Debug event listener which delegates. Exceptions have to be +// explictly caught here and checked later because exception in the +// listener are not propagated to the surrounding JavaScript code. +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + break_count++; + listener_called = true; + listener_delegate(exec_state); + } + } catch (e) { + exception = e; + } +} + +// Add the debug event listener. +Debug.setListener(listener); + + +// Initialize for a new test. +function BeginTest(name) { + test_name = name; + listener_called = false; + exception = null; + begin_test_count++; +} + + +// Check result of a test. +function EndTest() { + assertTrue(listener_called, "listerner not called for " + test_name); + assertNull(exception, test_name); + end_test_count++; +} + + +// Check that the debugger correctly reflects that the receiver is not +// converted to object for strict mode functions. +function Strict() { "use strict"; debugger; } +function TestStrict(receiver) { + expected_receiver = receiver; + Strict.call(receiver); +} + +listener_delegate = function(exec_state) { + var receiver = exec_state.frame().receiver(); + assertTrue(!receiver.isObject()); + assertEquals(expected_receiver, receiver.value()) +} + +BeginTest("strict: undefined"); TestStrict(undefined); EndTest(); +BeginTest("strict: null"); TestStrict(null); EndTest(); +BeginTest("strict: 1"); TestStrict(1); EndTest(); +BeginTest("strict: 1.2"); TestStrict(1.2); EndTest(); +BeginTest("strict: 'asdf'"); TestStrict('asdf'); EndTest(); +BeginTest("strict: true"); TestStrict(true); EndTest(); + + +// Check that the debugger correctly reflects the object conversion of +// the receiver for non-strict mode functions. +function NonStrict() { debugger; } +function TestNonStrict(receiver) { + // null and undefined should be transformed to the global object and + // primitives should be wrapped. + expected_receiver = (receiver == null) ? this : Object(receiver); + NonStrict.call(receiver); +} + +listener_delegate = function(exec_state) { + var receiver = exec_state.frame().receiver(); + assertTrue(receiver.isObject()); + assertEquals(expected_receiver, receiver.value()); +} + +BeginTest("non-strict: undefined"); TestNonStrict(undefined); EndTest(); +BeginTest("non-strict: null"); TestNonStrict(null); EndTest(); +BeginTest("non-strict: 1"); TestNonStrict(1); EndTest(); +BeginTest("non-strict: 1.2"); TestNonStrict(1.2); EndTest(); +BeginTest("non-strict: 'asdf'"); TestNonStrict('asdf'); EndTest(); +BeginTest("non-strict: true"); TestNonStrict(true); EndTest(); + + +assertEquals(begin_test_count, break_count, + 'one or more tests did not enter the debugger'); +assertEquals(begin_test_count, end_test_count, + 'one or more tests did not have its result checked'); diff --git a/deps/v8/test/mjsunit/harmony/proxies.js b/deps/v8/test/mjsunit/harmony/proxies.js index 37f351317..84641d589 100644 --- a/deps/v8/test/mjsunit/harmony/proxies.js +++ b/deps/v8/test/mjsunit/harmony/proxies.js @@ -28,6 +28,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// TODO(rossberg): test exception cases. + // Getters. @@ -289,6 +291,50 @@ TestDefine(Proxy.create({ +// Property deletion (delete). + +var key +function TestDelete(handler) { + var o = Proxy.create(handler) + assertEquals(true, delete o.a) + assertEquals("a", key) + assertEquals(true, delete o["b"]) + assertEquals("b", key) + + assertEquals(false, delete o.z1) + assertEquals("z1", key) + assertEquals(false, delete o["z2"]) + assertEquals("z2", key); + + (function() { + "use strict" + assertEquals(true, delete o.c) + assertEquals("c", key) + assertEquals(true, delete o["d"]) + assertEquals("d", key) + + assertThrows(function() { delete o.z3 }, TypeError) + assertEquals("z3", key) + assertThrows(function() { delete o["z4"] }, TypeError) + assertEquals("z4", key) + })() +} + +TestDelete({ + 'delete': function(k) { key = k; return k < "z" } +}) +TestDelete({ + 'delete': function(k) { return this.delete2(k) }, + delete2: function(k) { key = k; return k < "z" } +}) +TestDelete(Proxy.create({ + get: function(pr, pk) { + return function(k) { key = k; return k < "z" } + } +})) + + + // Property descriptors (Object.getOwnPropertyDescriptor). function TestDescriptor(handler) { @@ -358,6 +404,79 @@ assertTrue("object" == typeof Proxy.create({})) +// Element (in). + +var key +function TestIn(handler) { + var o = Proxy.create(handler) + assertTrue("a" in o) + assertEquals("a", key) + assertTrue(99 in o) + assertEquals("99", key) + assertFalse("z" in o) + assertEquals("z", key) + + if ("b" in o) { + } else { + assertTrue(false) + } + assertEquals("b", key) + + if ("zz" in o) { + assertTrue(false) + } + assertEquals("zz", key) + + if (!("c" in o)) { + assertTrue(false) + } + assertEquals("c", key) + + if (!("zzz" in o)) { + } else { + assertTrue(false) + } + assertEquals("zzz", key) +} + +TestIn({ + has: function(k) { key = k; return k < "z" } +}) +TestIn({ + has: function(k) { return this.has2(k) }, + has2: function(k) { key = k; return k < "z" } +}) +TestIn({ + getPropertyDescriptor: function(k) { + key = k; return k < "z" ? {value: 42} : void 0 + } +}) +TestIn({ + getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) }, + getPropertyDescriptor2: function(k) { + key = k; return k < "z" ? {value: 42} : void 0 + } +}) +TestIn({ + getPropertyDescriptor: function(k) { + key = k; return k < "z" ? {get value() { return 42 }} : void 0 + } +}) +TestIn({ + get: undefined, + getPropertyDescriptor: function(k) { + key = k; return k < "z" ? {value: 42} : void 0 + } +}) + +TestIn(Proxy.create({ + get: function(pr, pk) { + return function(k) { key = k; return k < "z" } + } +})) + + + // Instanceof (instanceof). function TestInstanceof() { @@ -485,3 +604,84 @@ TestKeys([], { }, getOwnPropertyDescriptor: function(k) { return {} } }) + + + +// Fixing (Object.freeze, Object.seal, Object.preventExtensions, +// Object.isFrozen, Object.isSealed, Object.isExtensible) + +function TestFix(names, handler) { + var proto = {p: 77} + var assertFixing = function(o, s, f, e) { + assertEquals(s, Object.isSealed(o)) + assertEquals(f, Object.isFrozen(o)) + assertEquals(e, Object.isExtensible(o)) + } + + var o1 = Proxy.create(handler, proto) + assertFixing(o1, false, false, true) + Object.seal(o1) + assertFixing(o1, true, names.length === 0, false) + assertArrayEquals(names.sort(), Object.getOwnPropertyNames(o1).sort()) + assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(), + Object.keys(o1).sort()) + assertEquals(proto, Object.getPrototypeOf(o1)) + assertEquals(77, o1.p) + for (var n in o1) { + var desc = Object.getOwnPropertyDescriptor(o1, n) + if (desc !== undefined) assertFalse(desc.configurable) + } + + var o2 = Proxy.create(handler, proto) + assertFixing(o2, false, false, true) + Object.freeze(o2) + assertFixing(o2, true, true, false) + assertArrayEquals(names.sort(), Object.getOwnPropertyNames(o2).sort()) + assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(), + Object.keys(o2).sort()) + assertEquals(proto, Object.getPrototypeOf(o2)) + assertEquals(77, o2.p) + for (var n in o2) { + var desc = Object.getOwnPropertyDescriptor(o2, n) + if (desc !== undefined) assertFalse(desc.writable) + if (desc !== undefined) assertFalse(desc.configurable) + } + + var o3 = Proxy.create(handler, proto) + assertFixing(o3, false, false, true) + Object.preventExtensions(o3) + assertFixing(o3, names.length === 0, names.length === 0, false) + assertArrayEquals(names.sort(), Object.getOwnPropertyNames(o3).sort()) + assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(), + Object.keys(o3).sort()) + assertEquals(proto, Object.getPrototypeOf(o3)) + assertEquals(77, o3.p) +} + +TestFix([], { + fix: function() { return {} } +}) +TestFix(["a", "b", "c", "d", "zz"], { + fix: function() { + return { + a: {value: "a", writable: true, configurable: false, enumerable: true}, + b: {value: 33, writable: false, configurable: false, enumerable: true}, + c: {value: 0, writable: true, configurable: true, enumerable: true}, + d: {value: true, writable: false, configurable: true, enumerable: true}, + zz: {value: 0, enumerable: false} + } + } +}) +TestFix(["a"], { + fix: function() { return this.fix2() }, + fix2: function() { + return {a: {value: 4, writable: true, configurable: true, enumerable: true}} + } +}) +TestFix(["b"], { + get fix() { + return function() { + return {b: {configurable: true, writable: true, enumerable: true}} + } + } +}) diff --git a/deps/v8/test/mjsunit/regress/regress-1560.js b/deps/v8/test/mjsunit/regress/regress-1560.js new file mode 100644 index 000000000..a0aa7e64d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-1560.js @@ -0,0 +1,68 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --allow-natives-syntax --expose-gc + +function mkCOWArray() { + var a = ['']; + assertEquals('', a[0]); + return a; +} + +function mkArray() { + var a = []; + a[0] = ''; + return a; +} + +function mkNumberDictionary() { + var a = new Array(); + a[0] = ''; + a[100000] = ''; + return a; +} + +function write(a, i) { a[i] = "bazinga!"; } + +function test(factories, w) { + factories.forEach(function(f) { w(f(), 0); }); + factories.forEach(function(f) { w(f(), 0); }); + %OptimizeFunctionOnNextCall(w); + factories.forEach(function(f) { w(f(), 0); }); +} + +// Monomorphic case. +for (var i = 0; i < 5; i++) write(mkArray(), 0); +%OptimizeFunctionOnNextCall(write); +write(mkCOWArray(), 0); +var failure = mkCOWArray(); + +// Cleanup, then polymorphic case. +%DeoptimizeFunction(write); +gc(); +test([mkArray, mkNumberDictionary], write); +test([mkArray, mkNumberDictionary, mkCOWArray], write); diff --git a/deps/v8/test/mjsunit/regress/regress-798.js b/deps/v8/test/mjsunit/regress/regress-798.js index 423c8832a..ffee5da91 100644 --- a/deps/v8/test/mjsunit/regress/regress-798.js +++ b/deps/v8/test/mjsunit/regress/regress-798.js @@ -106,4 +106,3 @@ xx.c; xx.a = 1; xx.b = 1; xx.c = 1; - diff --git a/deps/v8/test/mjsunit/unbox-double-arrays.js b/deps/v8/test/mjsunit/unbox-double-arrays.js index 31918b376..351765eec 100644 --- a/deps/v8/test/mjsunit/unbox-double-arrays.js +++ b/deps/v8/test/mjsunit/unbox-double-arrays.js @@ -27,52 +27,442 @@ // Test dictionary -> double elements -> dictionary elements round trip -var foo = new Array(500000); +// Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc +var large_array_size = 100000; +var approx_dict_to_elements_threshold = 75000; -function func(a) { - for (var i= 0; i < 100000; ++i ) { - a[i] = i+0.5; +var name = 0; + +function expected_array_value(i) { + if ((i % 2) == 0) { + return i; + } else { + return i + 0.5; + } +} + +function force_to_fast_double_array(a) { + a[large_array_size - 2] = 1; + for (var i= 0; i < approx_dict_to_elements_threshold; ++i ) { + a[i] = expected_array_value(i); } + assertTrue(%HasFastDoubleElements(a)); } -func(foo); +function make_object_like_array(size) { + obj = new Object(); + obj.length = size; + return obj; +} + +function testOneArrayType(allocator) { + var large_array = new allocator(large_array_size); + force_to_fast_double_array(large_array); + var six = 6; + + for (var i= 0; i < approx_dict_to_elements_threshold; i += 501 ) { + assertEquals(expected_array_value(i), large_array[i]); + } + + // This function has a constant and won't get inlined. + function computed_6() { + return six; + } + + // Multiple versions of the test function makes sure that IC/Crankshaft state + // doesn't get reused. + function test_various_loads(a, value_5, value_6, value_7) { + assertTrue(%HasFastDoubleElements(a)); + assertEquals(value_5, a[5]); + assertEquals(value_6, a[6]); + assertEquals(value_6, a[computed_6()]); // Test non-constant key + assertEquals(value_7, a[7]); + assertEquals(undefined, a[large_array_size-1]); + assertEquals(undefined, a[-1]); + assertEquals(large_array_size, a.length); + assertTrue(%HasFastDoubleElements(a)); + } + + function test_various_loads2(a, value_5, value_6, value_7) { + assertTrue(%HasFastDoubleElements(a)); + assertEquals(value_5, a[5]); + assertEquals(value_6, a[6]); + assertEquals(value_6, a[computed_6()]); // Test non-constant key + assertEquals(value_7, a[7]); + assertEquals(undefined, a[large_array_size-1]); + assertEquals(undefined, a[-1]); + assertEquals(large_array_size, a.length); + assertTrue(%HasFastDoubleElements(a)); + } + + function test_various_loads3(a, value_5, value_6, value_7) { + assertTrue(%HasFastDoubleElements(a)); + assertEquals(value_5, a[5]); + assertEquals(value_6, a[6]); + assertEquals(value_6, a[computed_6()]); // Test non-constant key + assertEquals(value_7, a[7]); + assertEquals(undefined, a[large_array_size-1]); + assertEquals(undefined, a[-1]); + assertEquals(large_array_size, a.length); + assertTrue(%HasFastDoubleElements(a)); + } + + function test_various_loads4(a, value_5, value_6, value_7) { + assertTrue(%HasFastDoubleElements(a)); + assertEquals(value_5, a[5]); + assertEquals(value_6, a[6]); + assertEquals(value_6, a[computed_6()]); // Test non-constant key + assertEquals(value_7, a[7]); + assertEquals(undefined, a[large_array_size-1]); + assertEquals(undefined, a[-1]); + assertEquals(large_array_size, a.length); + assertTrue(%HasFastDoubleElements(a)); + } + + function test_various_loads5(a, value_5, value_6, value_7) { + assertTrue(%HasFastDoubleElements(a)); + assertEquals(value_5, a[5]); + assertEquals(value_6, a[6]); + assertEquals(value_6, a[computed_6()]); // Test non-constant key + assertEquals(value_7, a[7]); + assertEquals(undefined, a[large_array_size-1]); + assertEquals(undefined, a[-1]); + assertEquals(large_array_size, a.length); + assertTrue(%HasFastDoubleElements(a)); + } + + function test_various_loads6(a, value_5, value_6, value_7) { + assertTrue(%HasFastDoubleElements(a)); + assertEquals(value_5, a[5]); + assertEquals(value_6, a[6]); + assertEquals(value_6, a[computed_6()]); // Test non-constant key + assertEquals(value_7, a[7]); + assertEquals(undefined, a[large_array_size-1]); + assertEquals(undefined, a[-1]); + assertEquals(large_array_size, a.length); + assertTrue(%HasFastDoubleElements(a)); + } + + function test_various_stores(a, value_5, value_6, value_7) { + assertTrue(%HasFastDoubleElements(a)); + a[5] = value_5; + a[computed_6()] = value_6; + a[7] = value_7; + assertTrue(%HasFastDoubleElements(a)); + } + + // Test double and integer values + test_various_loads(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + test_various_loads(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + test_various_loads(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + %OptimizeFunctionOnNextCall(test_various_loads); + test_various_loads(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + + // Test NaN values + test_various_stores(large_array, NaN, -NaN, expected_array_value(7)); + + test_various_loads2(large_array, + NaN, + -NaN, + expected_array_value(7)); + test_various_loads2(large_array, + NaN, + -NaN, + expected_array_value(7)); + test_various_loads2(large_array, + NaN, + -NaN, + expected_array_value(7)); + %OptimizeFunctionOnNextCall(test_various_loads2); + test_various_loads2(large_array, + NaN, + -NaN, + expected_array_value(7)); + + // Test Infinity values + test_various_stores(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + + test_various_loads3(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + test_various_loads3(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + test_various_loads3(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + %OptimizeFunctionOnNextCall(test_various_loads3); + test_various_loads3(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + + // Test the hole for the default runtime implementation. + delete large_array[5]; + delete large_array[6]; + test_various_loads4(large_array, + undefined, + undefined, + expected_array_value(7)); + + // Test the keyed load IC implementation when the value is the hole. + test_various_stores(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + test_various_loads5(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + test_various_loads5(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + delete large_array[5]; + delete large_array[6]; + test_various_loads5(large_array, + undefined, + undefined, + expected_array_value(7)); + test_various_loads5(large_array, + undefined, + undefined, + expected_array_value(7)); -for (var i= 0; i < 100000; i += 500 ) { - assertEquals(i+0.5, foo[i]); + // Make sure Crankshaft code handles the hole correctly (bailout) + test_various_stores(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + test_various_loads6(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + test_various_loads6(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + %OptimizeFunctionOnNextCall(test_various_loads6); + test_various_loads6(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + + delete large_array[5]; + delete large_array[6]; + test_various_loads6(large_array, + undefined, + undefined, + expected_array_value(7)); + + // Test stores for non-NaN. + %OptimizeFunctionOnNextCall(test_various_stores); + test_various_stores(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + + test_various_stores(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + + test_various_loads6(large_array, + expected_array_value(5), + expected_array_value(6), + expected_array_value(7)); + + // Test NaN behavior for stores. + test_various_stores(large_array, + NaN, + -NaN, + expected_array_value(7)); + + test_various_stores(large_array, + NaN, + -NaN, + expected_array_value(7)); + + test_various_loads6(large_array, + NaN, + -NaN, + expected_array_value(7)); + + // Test Infinity behavior for stores. + test_various_stores(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + + test_various_stores(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + + test_various_loads6(large_array, + Infinity, + -Infinity, + expected_array_value(7)); + + assertTrue(%GetOptimizationStatus(test_various_stores) != 2); + + // Make sure that we haven't converted from fast double. + assertTrue(%HasFastDoubleElements(large_array)); } -delete foo[5]; -// Don't use assertEquals for comparison to undefined due to -assertTrue(undefined === foo[5]); -assertTrue(undefined === foo[500000-1]); -assertTrue(undefined === foo[-1]); -assertEquals(500000, foo.length); +testOneArrayType(make_object_like_array); +testOneArrayType(Array); + +var large_array = new Array(large_array_size); +force_to_fast_double_array(large_array); +assertTrue(%HasFastDoubleElements(large_array)); // Cause the array to grow beyond it's JSArray length. This will double the // size of the capacity and force the array into "slow" dictionary case. -foo[500001] = 50; -assertEquals(50, foo[500001]); -assertEquals(500002, foo.length); -assertTrue(undefined === foo[5]) -assertTrue(undefined === foo[500000-1]) -assertTrue(undefined === foo[-1]) -assertEquals(500002, foo.length); +large_array[5] = Infinity; +large_array[large_array_size+10001] = 50; +assertTrue(%HasDictionaryElements(large_array)); +assertEquals(50, large_array[large_array_size+10001]); +assertEquals(large_array_size+10002, large_array.length); +assertEquals(Infinity, large_array[5]); +assertEquals(undefined, large_array[large_array_size-1]); +assertEquals(undefined, large_array[-1]); +assertEquals(large_array_size+10002, large_array.length); // Test dictionary -> double elements -> fast elements. - -var foo2 = new Array(500000); -func(foo2); -delete foo2[5]; +var large_array2 = new Array(large_array_size); +force_to_fast_double_array(large_array2); +delete large_array2[5]; // Convert back to fast elements and make sure the contents of the array are // unchanged. -foo2[25] = new Object(); -for (var i= 0; i < 100000; i += 500 ) { +large_array2[25] = new Object(); +assertTrue(%HasFastElements(large_array2)); +for (var i= 0; i < approx_dict_to_elements_threshold; i += 500 ) { if (i != 25 && i != 5) { - assertEquals(i+0.5, foo2[i]); + assertEquals(expected_array_value(i), large_array2[i]); } } -assertTrue(undefined === foo2[5]) -assertTrue(undefined === foo2[500000-1]) -assertTrue(undefined === foo2[-1]) -assertEquals(500000, foo2.length); +assertEquals(undefined, large_array2[5]); +assertEquals(undefined, large_array2[large_array_size-1]); +assertEquals(undefined, large_array2[-1]); +assertEquals(large_array_size, large_array2.length); + +// Make sure it's possible to change the array's length and that array is still +// intact after the resize. +var large_array3 = new Array(large_array_size); +force_to_fast_double_array(large_array3); +large_array3.length = 60000; +assertEquals(60000, large_array3.length); +assertEquals(undefined, large_array3[60000]); +assertTrue(%HasFastDoubleElements(large_array3)); +assertEquals(expected_array_value(5), large_array3[5]); +assertEquals(expected_array_value(6), large_array3[6]); +assertEquals(expected_array_value(7), large_array3[7]); +assertEquals(expected_array_value(large_array3.length-1), + large_array3[large_array3.length-1]); +assertEquals(undefined, large_array3[large_array_size-1]); +assertEquals(undefined, large_array3[-1]); +gc(); + +for (var i= 0; i < large_array3.length; i += 501 ) { + assertEquals(expected_array_value(i), large_array3[i]); +} + +large_array3.length = 25; +assertEquals(25, large_array3.length); +assertTrue(%HasFastDoubleElements(large_array3)); +assertEquals(undefined, large_array3[25]); +assertEquals(expected_array_value(5), large_array3[5]); +assertEquals(expected_array_value(6), large_array3[6]); +assertEquals(expected_array_value(7), large_array3[7]); +assertEquals(expected_array_value(large_array3.length-1), + large_array3[large_array3.length-1]); +assertEquals(undefined, large_array3[large_array_size-1]); +assertEquals(undefined, large_array3[-1]); +gc(); + +for (var i= 0; i < large_array3.length; ++i) { + assertEquals(expected_array_value(i), large_array3[i]); +} + +large_array3.length = 100; +assertEquals(100, large_array3.length); +large_array3[95] = 95; +assertTrue(%HasFastDoubleElements(large_array3)); +assertEquals(undefined, large_array3[100]); +assertEquals(95, large_array3[95]); +assertEquals(expected_array_value(5), large_array3[5]); +assertEquals(expected_array_value(6), large_array3[6]); +assertEquals(expected_array_value(7), large_array3[7]); +assertEquals(undefined, large_array3[large_array3.length-1]); +assertEquals(undefined, large_array3[large_array_size-1]); +assertEquals(undefined, large_array3[-1]); +gc(); + +// Test apply on arrays backed by double elements. +function called_by_apply(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + assertEquals(expected_array_value(0), arg0); + assertEquals(NaN, arg1); + assertEquals(-NaN, arg2); + assertEquals(Infinity, arg3); + assertEquals(-Infinity, arg4); + assertEquals(expected_array_value(5), arg5); +} + +large_array3[1] = NaN; +large_array3[2] = -NaN; +large_array3[3] = Infinity; +large_array3[4] = -Infinity; + +function call_apply() { + assertTrue(%HasFastDoubleElements(large_array3)); + called_by_apply.apply({}, large_array3); +} + +call_apply(); +call_apply(); +call_apply(); +%OptimizeFunctionOnNextCall(call_apply); +call_apply(); +call_apply(); +call_apply(); + +function test_for_in() { + // Due to previous tests, keys 0..25 and 95 should be present. + next_expected = 0; + assertTrue(%HasFastDoubleElements(large_array3)); + for (x in large_array3) { + assertTrue(next_expected++ == x); + if (next_expected == 25) { + next_expected = 95; + } + } + assertTrue(next_expected == 96); +} + +test_for_in(); +test_for_in(); +test_for_in(); +%OptimizeFunctionOnNextCall(test_for_in); +test_for_in(); +test_for_in(); +test_for_in(); diff --git a/deps/v8/test/test262/test262.status b/deps/v8/test/test262/test262.status index f68b85db7..8cee21076 100644 --- a/deps/v8/test/test262/test262.status +++ b/deps/v8/test/test262/test262.status @@ -1138,33 +1138,6 @@ prefix ietestcenter 15.4.4.20-1-5: FAIL # Bug? Array.prototype.filter applied to string primitive 15.4.4.20-1-7: FAIL -# Bug? Array.prototype.filter - value of 'length' is a number (value is -# negative) -15.4.4.20-3-7: FAIL -# Bug? Array.prototype.filter - value of 'length' is a number (value is -# Infinity) -# V8 timeout -15.4.4.20-3-8: SKIP -# Bug? Array.prototype.filter - 'length' is a string containing a negative -# number -15.4.4.20-3-12: FAIL -# Bug? Array.prototype.filter - 'length' is a string containing a decimal number -15.4.4.20-3-13: FAIL -# Bug? Array.prototype.filter - 'length' is a string containing +/-Infinity -15.4.4.20-3-14: SKIP -# Bug? Array.prototype.filter - value of 'length' is a positive non-integer, -# ensure truncation occurs in the proper direction -# V8 timeout -15.4.4.20-3-24: FAIL -# Bug? Array.prototype.filter - value of 'length' is a negative non-integer, -# ensure truncation occurs in the proper direction -15.4.4.20-3-25: FAIL -# Bug? Array.prototype.filter - value of 'length' is boundary value (2^32) -# V8 timeout -15.4.4.20-3-28: SKIP -# Bug? Array.prototype.filter - value of 'length' is boundary value (2^32 + 1) -# V8 timeout -15.4.4.20-3-29: SKIP # Bug? Array.prototype.filter - side effects produced by step 2 are visible when # an exception occurs 15.4.4.20-4-8: FAIL @@ -1220,33 +1193,6 @@ prefix ietestcenter 15.4.4.21-1-5: FAIL # Bug? Array.prototype.reduce applied to string primitive 15.4.4.21-1-7: FAIL -# Bug? Array.prototype.reduce - value of 'length' is a number (value is -# negative) -15.4.4.21-3-7: FAIL -# Bug? Array.prototype.reduce - value of 'length' is a number (value is -# Infinity) -# V8 timeout. -15.4.4.21-3-8: SKIP -# Bug? Array.prototype.reduce - 'length' is a string containing a negative -# number -15.4.4.21-3-12: FAIL -# Bug? Array.prototype.reduce - 'length' is a string containing a decimal number -15.4.4.21-3-13: FAIL -# Bug? Array.prototype.reduce - 'length' is a string containing +/-Infinity -# V8 timeout. -15.4.4.21-3-14: SKIP -# Bug? Array.prototype.reduce - value of 'length' is a positive non-integer, -# ensure truncation occurs in the proper direction -15.4.4.21-3-24: FAIL -# Bug? Array.prototype.reduce - value of 'length' is a negative non-integer, -# ensure truncation occurs in the proper direction -15.4.4.21-3-25: FAIL -# Bug? Array.prototype.reduce - value of 'length' is boundary value (2^32) -# V8 timeout. -15.4.4.21-3-28: SKIP -# Bug? Array.prototype.reduce - value of 'length' is boundary value (2^32 + 1) -# V8 timeout. -15.4.4.21-3-29: SKIP # Bug? Array.prototype.reduce - side effects produced by step 2 are visible when # an exception occurs 15.4.4.21-4-8: FAIL @@ -1274,36 +1220,6 @@ prefix ietestcenter 15.4.4.22-1-5: FAIL # Bug? Array.prototype.reduceRight applied to string primitive 15.4.4.22-1-7: FAIL -# Bug? Array.prototype.reduceRight - value of 'length' is a number (value is -# negative) -15.4.4.22-3-7: FAIL -# Bug? Array.prototype.reduceRight - value of 'length' is a number (value is -# Infinity) -# V8 timeout. -15.4.4.22-3-8: SKIP -# Bug? Array.prototype.reduceRight - value of 'length' is a string containing a -# negative number -15.4.4.22-3-12: FAIL -# Bug? Array.prototype.reduceRight - value of 'length' is a string containing a -# decimal number -15.4.4.22-3-13: FAIL -# Bug? Array.prototype.reduceRight - value of 'length' is a string containing -# +/-Infinity -# V8 timeout. -15.4.4.22-3-14: SKIP -# Bug? Array.prototype.reduceRight - value of 'length' is a positive -# non-integer, ensure truncation occurs in the proper direction -15.4.4.22-3-24: FAIL -# Bug? Array.prototype.reduceRight - value of 'length' is a negative -# non-integer, ensure truncation occurs in the proper direction -15.4.4.22-3-25: FAIL -# Bug? Array.prototype.reduceRight - value of 'length' is boundary value (2^32) -# V8 timeout. -15.4.4.22-3-28: SKIP -# Bug? Array.prototype.reduceRight - value of 'length' is boundary value (2^32 + -# 1) -# V8 timeout. -15.4.4.22-3-29: SKIP # Bug? Array.prototype.reduceRight - side effects produced by step 2 are visible # when an exception occurs 15.4.4.22-4-8: FAIL diff --git a/deps/v8/tools/grokdump.py b/deps/v8/tools/grokdump.py index 74521ad21..468e7cc6b 100755 --- a/deps/v8/tools/grokdump.py +++ b/deps/v8/tools/grokdump.py @@ -291,6 +291,7 @@ class MinidumpReader(object): self.exception = None self.exception_context = None self.memory_list = None + self.memory_list64 = None self.thread_map = {} for d in directories: DebugPrint(d) @@ -311,16 +312,17 @@ class MinidumpReader(object): self.thread_map[thread.id] = thread elif d.stream_type == MD_MEMORY_LIST_STREAM: print >>sys.stderr, "Warning: not a full minidump" - ml = MINIDUMP_MEMORY_LIST.Read(self.minidump, d.location.rva) - DebugPrint(ml) - for m in ml.ranges: - DebugPrint(m) - elif d.stream_type == MD_MEMORY_64_LIST_STREAM: assert self.memory_list is None - self.memory_list = MINIDUMP_MEMORY_LIST64.Read( + self.memory_list = MINIDUMP_MEMORY_LIST.Read( self.minidump, d.location.rva) assert ctypes.sizeof(self.memory_list) == d.location.data_size DebugPrint(self.memory_list) + elif d.stream_type == MD_MEMORY_64_LIST_STREAM: + assert self.memory_list64 is None + self.memory_list64 = MINIDUMP_MEMORY_LIST64.Read( + self.minidump, d.location.rva) + assert ctypes.sizeof(self.memory_list64) == d.location.data_size + DebugPrint(self.memory_list64) def IsValidAddress(self, address): return self.FindLocation(address) is not None @@ -338,12 +340,16 @@ class MinidumpReader(object): return self.minidump[location:location + size] def FindLocation(self, address): - # TODO(vitalyr): only works for full minidumps (...64 structure variants). offset = 0 - for r in self.memory_list.ranges: - if r.start <= address < r.start + r.size: - return self.memory_list.base_rva + offset + address - r.start + if self.memory_list64 is not None: + for r in self.memory_list64.ranges: + if r.start <= address < r.start + r.size: + return self.memory_list64.base_rva + offset + address - r.start offset += r.size + if self.memory_list is not None: + for r in self.memory_list.ranges: + if r.start <= address < r.start + r.memory.data_size: + return r.memory.rva + address - r.start return None def GetDisasmLines(self, address, size): |