From 50f45d14b475a42d304e7d9872f8d91ff3a013c2 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 28 Oct 2009 19:25:22 +0100 Subject: [PATCH] Upgrade v8 to 1.3.17 --- deps/v8/ChangeLog | 21 +- deps/v8/include/v8.h | 63 +- deps/v8/src/api.cc | 60 +- deps/v8/src/api.h | 9 + deps/v8/src/arm/assembler-arm-inl.h | 6 + deps/v8/src/arm/assembler-arm.h | 8 + deps/v8/src/arm/builtins-arm.cc | 4 + deps/v8/src/arm/codegen-arm.cc | 56 +- deps/v8/src/arm/codegen-arm.h | 9 +- deps/v8/src/arm/fast-codegen-arm.cc | 584 ++++++++++++- deps/v8/src/arm/frames-arm.cc | 15 +- deps/v8/src/arm/frames-arm.h | 2 +- deps/v8/src/arm/ic-arm.cc | 14 + deps/v8/src/arm/macro-assembler-arm.cc | 19 +- deps/v8/src/arm/macro-assembler-arm.h | 8 +- deps/v8/src/arm/regexp-macro-assembler-arm.cc | 15 +- deps/v8/src/arm/regexp-macro-assembler-arm.h | 15 + deps/v8/src/arm/virtual-frame-arm.cc | 34 +- deps/v8/src/assembler.cc | 25 + deps/v8/src/assembler.h | 8 + deps/v8/src/ast.cc | 8 + deps/v8/src/ast.h | 2 + deps/v8/src/bootstrapper.cc | 3 + deps/v8/src/builtins.cc | 76 ++ deps/v8/src/builtins.h | 90 +- deps/v8/src/code-stubs.cc | 91 +- deps/v8/src/code-stubs.h | 67 +- deps/v8/src/codegen.cc | 18 +- deps/v8/src/codegen.h | 29 +- deps/v8/src/compiler.cc | 241 +++++- deps/v8/src/conversions-inl.h | 2 +- deps/v8/src/conversions.cc | 2 +- deps/v8/src/conversions.h | 1 + deps/v8/src/debug-delay.js | 10 +- deps/v8/src/factory.cc | 12 + deps/v8/src/factory.h | 9 +- deps/v8/src/fast-codegen.cc | 197 ++++- deps/v8/src/fast-codegen.h | 27 +- deps/v8/src/flag-definitions.h | 6 +- deps/v8/src/frames.cc | 18 +- deps/v8/src/frames.h | 25 +- deps/v8/src/global-handles.cc | 101 ++- deps/v8/src/global-handles.h | 18 + deps/v8/src/globals.h | 18 +- deps/v8/src/handles.cc | 17 +- deps/v8/src/handles.h | 10 +- deps/v8/src/heap-profiler.cc | 44 +- deps/v8/src/heap-profiler.h | 4 +- deps/v8/src/heap.cc | 308 +++++-- deps/v8/src/heap.h | 84 +- deps/v8/src/ia32/assembler-ia32.cc | 18 +- deps/v8/src/ia32/assembler-ia32.h | 10 + deps/v8/src/ia32/builtins-ia32.cc | 86 +- deps/v8/src/ia32/codegen-ia32.cc | 303 ++++--- deps/v8/src/ia32/codegen-ia32.h | 27 +- deps/v8/src/ia32/disasm-ia32.cc | 272 +++--- deps/v8/src/ia32/fast-codegen-ia32.cc | 584 ++++++++++++- deps/v8/src/ia32/frames-ia32.cc | 13 +- deps/v8/src/ia32/frames-ia32.h | 2 +- deps/v8/src/ia32/ic-ia32.cc | 367 +++++++- deps/v8/src/ia32/macro-assembler-ia32.cc | 130 ++- deps/v8/src/ia32/macro-assembler-ia32.h | 25 +- .../src/ia32/regexp-macro-assembler-ia32.cc | 20 +- deps/v8/src/ia32/stub-cache-ia32.cc | 39 +- deps/v8/src/ic.cc | 69 +- deps/v8/src/ic.h | 16 + deps/v8/src/list.h | 1 + deps/v8/src/location.h | 7 +- deps/v8/src/log.cc | 32 +- deps/v8/src/objects-debug.cc | 176 ++++ deps/v8/src/objects-inl.h | 286 +++++- deps/v8/src/objects.cc | 374 +++++++- deps/v8/src/objects.h | 273 +++++- deps/v8/src/platform-nullos.cc | 7 + deps/v8/src/platform-posix.cc | 6 + deps/v8/src/platform-win32.cc | 50 +- deps/v8/src/platform.h | 1 + deps/v8/src/regexp-macro-assembler.h | 16 - deps/v8/src/runtime.cc | 178 +++- deps/v8/src/runtime.h | 4 + deps/v8/src/runtime.js | 5 +- deps/v8/src/serialize.cc | 508 +++++++++++ deps/v8/src/serialize.h | 230 ++++- deps/v8/src/snapshot-common.cc | 56 ++ deps/v8/src/snapshot.h | 3 + deps/v8/src/spaces-inl.h | 7 + deps/v8/src/spaces.cc | 42 +- deps/v8/src/spaces.h | 14 + deps/v8/src/string-stream.cc | 2 +- deps/v8/src/string.js | 9 +- deps/v8/src/stub-cache.cc | 7 +- deps/v8/src/third_party/valgrind/valgrind.h | 57 +- deps/v8/src/top.h | 4 + deps/v8/src/v8-counters.h | 1 + deps/v8/src/v8.cc | 2 +- deps/v8/src/v8.h | 2 +- deps/v8/src/version.cc | 2 +- deps/v8/src/x64/assembler-x64.cc | 86 +- deps/v8/src/x64/assembler-x64.h | 27 +- deps/v8/src/x64/builtins-x64.cc | 78 +- deps/v8/src/x64/codegen-x64.cc | 476 ++++++---- deps/v8/src/x64/codegen-x64.h | 85 +- deps/v8/src/x64/cpu-x64.cc | 13 + deps/v8/src/x64/disasm-x64.cc | 365 ++++---- deps/v8/src/x64/fast-codegen-x64.cc | 583 ++++++++++++- deps/v8/src/x64/frames-x64.cc | 14 +- deps/v8/src/x64/frames-x64.h | 2 +- deps/v8/src/x64/ic-x64.cc | 326 ++++++- deps/v8/src/x64/macro-assembler-x64.cc | 134 ++- deps/v8/src/x64/macro-assembler-x64.h | 43 +- deps/v8/src/x64/regexp-macro-assembler-x64.cc | 23 +- deps/v8/test/cctest/SConscript | 1 + deps/v8/test/cctest/cctest.cc | 3 + deps/v8/test/cctest/cctest.h | 136 +++ deps/v8/test/cctest/cctest.status | 15 + deps/v8/test/cctest/test-accessors.cc | 424 +++++++++ deps/v8/test/cctest/test-api.cc | 813 ++++++++++-------- deps/v8/test/cctest/test-debug.cc | 6 - deps/v8/test/cctest/test-log-stack-tracer.cc | 22 +- deps/v8/test/cctest/test-log.cc | 5 +- .../test/cctest/test-macro-assembler-x64.cc | 10 +- deps/v8/test/cctest/test-mark-compact.cc | 5 - deps/v8/test/cctest/test-serialize.cc | 70 ++ deps/v8/test/cctest/test-spaces.cc | 20 +- deps/v8/test/mjsunit/compiler/globals.js | 55 ++ .../mjsunit/compiler/literals-assignment.js | 33 + deps/v8/test/mjsunit/compiler/literals.js | 17 + .../test/mjsunit/compiler/property-simple.js | 39 + deps/v8/test/mjsunit/debug-version.js | 90 ++ deps/v8/test/mjsunit/div-mod.js | 69 ++ deps/v8/test/mjsunit/fuzz-natives.js | 5 +- deps/v8/test/mjsunit/mjsunit.status | 3 + deps/v8/test/mjsunit/regress/regress-475.js | 28 + deps/v8/test/mjsunit/regress/regress-483.js | 35 + deps/v8/test/mjsunit/regress/regress-485.js | 64 ++ deps/v8/tools/test.py | 12 +- 136 files changed, 9070 insertions(+), 2021 deletions(-) create mode 100644 deps/v8/test/cctest/test-accessors.cc create mode 100644 deps/v8/test/mjsunit/compiler/globals.js create mode 100644 deps/v8/test/mjsunit/compiler/property-simple.js create mode 100644 deps/v8/test/mjsunit/debug-version.js create mode 100644 deps/v8/test/mjsunit/regress/regress-475.js create mode 100644 deps/v8/test/mjsunit/regress/regress-483.js create mode 100644 deps/v8/test/mjsunit/regress/regress-485.js diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index d13d74f545..e816f5833f 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,22 @@ +2009-10-28: Version 1.3.17 + + Added API method to get simple heap statistics. + + Improved heap profiler support. + + Fixed the implementation of the resource constraint API so it + works when using snapshots. + + Fixed a number of issues in the Windows 64-bit version. + + Optimized calls to API getters. + + Added valgrind notification on code modification to the 64-bit version. + + Fixed issue where we logged shared library addresses on Windows at + startup and never used them. + + 2009-10-16: Version 1.3.16 X64: Convert smis to holding 32 bits of payload. @@ -41,7 +60,7 @@ Ensure V8 is initialized before locking and unlocking threads. Implemented a new JavaScript minifier for compressing the source of - the built-in JavaScript. This Remove non-Open Source code from Douglas + the built-in JavaScript. This removes non-Open Source code from Douglas Crockford from the project. Added a missing optimization in StringCharAt. diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index d923f97855..5f3b68b227 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -452,8 +452,8 @@ class V8EXPORT HandleScope { void* operator new(size_t size); void operator delete(void*, size_t); - // This Data class is accessible internally through a typedef in the - // ImplementationUtilities class. + // This Data class is accessible internally as HandleScopeData through a + // typedef in the ImplementationUtilities class. class V8EXPORT Data { public: int extensions; @@ -1069,7 +1069,7 @@ class V8EXPORT Number : public Primitive { class V8EXPORT Integer : public Number { public: static Local New(int32_t value); - static inline Local NewFromUnsigned(uint32_t value); + static Local NewFromUnsigned(uint32_t value); int64_t Value() const; static inline Integer* Cast(v8::Value* obj); private: @@ -1126,6 +1126,16 @@ enum PropertyAttribute { DontDelete = 1 << 2 }; +enum ExternalArrayType { + kExternalByteArray = 1, + kExternalUnsignedByteArray, + kExternalShortArray, + kExternalUnsignedShortArray, + kExternalIntArray, + kExternalUnsignedIntArray, + kExternalFloatArray +}; + /** * A JavaScript object (ECMA-262, 4.3.3) */ @@ -1278,6 +1288,17 @@ class V8EXPORT Object : public Value { */ void SetIndexedPropertiesToPixelData(uint8_t* data, int length); + /** + * Set the backing store of the indexed properties to be managed by the + * embedding layer. Access to the indexed properties will follow the rules + * spelled out for the CanvasArray subtypes in the WebGL specification. + * Note: The embedding program still owns the data and needs to ensure that + * the backing store is preserved while V8 has a reference. + */ + void SetIndexedPropertiesToExternalArrayData(void* data, + ExternalArrayType array_type, + int number_of_elements); + static Local New(); static inline Object* Cast(Value* obj); private: @@ -2102,6 +2123,29 @@ enum ProfilerModules { }; +/** + * Collection of V8 heap information. + * + * Instances of this class can be passed to v8::V8::HeapStatistics to + * get heap statistics from V8. + */ +class V8EXPORT HeapStatistics { + public: + HeapStatistics(); + size_t total_heap_size() { return total_heap_size_; } + size_t used_heap_size() { return used_heap_size_; } + + private: + void set_total_heap_size(size_t size) { total_heap_size_ = size; } + void set_used_heap_size(size_t size) { used_heap_size_ = size; } + + size_t total_heap_size_; + size_t used_heap_size_; + + friend class V8; +}; + + /** * Container class for static utility functions. */ @@ -2352,6 +2396,10 @@ class V8EXPORT V8 { */ static bool Dispose(); + /** + * Get statistics about the heap memory usage. + */ + static void GetHeapStatistics(HeapStatistics* heap_statistics); /** * Optional notification that the embedder is idle. @@ -3069,15 +3117,6 @@ Number* Number::Cast(v8::Value* value) { } -Local Integer::NewFromUnsigned(uint32_t value) { - bool fits_into_int32_t = (value & (1 << 31)) == 0; - if (fits_into_int32_t) { - return Integer::New(static_cast(value)); - } - return Local::Cast(Number::New(value)); -} - - Integer* Integer::Cast(v8::Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index ffbe98eaf6..2d11c49f16 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -342,10 +342,10 @@ ResourceConstraints::ResourceConstraints() bool SetResourceConstraints(ResourceConstraints* constraints) { - int semispace_size = constraints->max_young_space_size(); + int young_space_size = constraints->max_young_space_size(); int old_gen_size = constraints->max_old_space_size(); - if (semispace_size != 0 || old_gen_size != 0) { - bool result = i::Heap::ConfigureHeap(semispace_size, old_gen_size); + if (young_space_size != 0 || old_gen_size != 0) { + bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size); if (!result) return false; } if (constraints->stack_limit() != NULL) { @@ -2306,6 +2306,30 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) { } +void v8::Object::SetIndexedPropertiesToExternalArrayData( + void* data, + ExternalArrayType array_type, + int length) { + ON_BAILOUT("v8::SetIndexedPropertiesToExternalArrayData()", return); + ENTER_V8; + HandleScope scope; + if (!ApiCheck(length <= i::ExternalArray::kMaxLength, + "v8::Object::SetIndexedPropertiesToExternalArrayData()", + "length exceeds max acceptable value")) { + return; + } + i::Handle self = Utils::OpenHandle(this); + if (!ApiCheck(!self->IsJSArray(), + "v8::Object::SetIndexedPropertiesToExternalArrayData()", + "JSArray is not supported")) { + return; + } + i::Handle array = + i::Factory::NewExternalArray(length, array_type, data); + self->set_elements(*array); +} + + Local Function::NewInstance() const { return NewInstance(0, NULL); } @@ -2611,6 +2635,15 @@ bool v8::V8::Dispose() { } +HeapStatistics::HeapStatistics(): total_heap_size_(0), used_heap_size_(0) { } + + +void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { + heap_statistics->set_total_heap_size(i::Heap::CommittedMemory()); + heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects()); +} + + bool v8::V8::IdleNotification() { // Returning true tells the caller that it need not // continue to call IdleNotification. @@ -2620,10 +2653,8 @@ bool v8::V8::IdleNotification() { void v8::V8::LowMemoryNotification() { -#if defined(ANDROID) if (!i::V8::IsRunning()) return; i::Heap::CollectAllGarbage(true); -#endif } @@ -3152,6 +3183,10 @@ Local v8::Object::New() { Local v8::Date::New(double time) { EnsureInitialized("v8::Date::New()"); LOG_API("Date::New"); + if (isnan(time)) { + // Introduce only canonical NaN value into the VM, to avoid signaling NaNs. + time = i::OS::nan_value(); + } ENTER_V8; EXCEPTION_PREAMBLE(); i::Handle obj = @@ -3224,6 +3259,10 @@ Local v8::String::NewSymbol(const char* data, int length) { Local v8::Number::New(double value) { EnsureInitialized("v8::Number::New()"); + if (isnan(value)) { + // Introduce only canonical NaN value into the VM, to avoid signaling NaNs. + value = i::OS::nan_value(); + } ENTER_V8; i::Handle result = i::Factory::NewNumber(value); return Utils::NumberToLocal(result); @@ -3241,6 +3280,17 @@ Local v8::Integer::New(int32_t value) { } +Local Integer::NewFromUnsigned(uint32_t value) { + bool fits_into_int32_t = (value & (1 << 31)) == 0; + if (fits_into_int32_t) { + return Integer::New(static_cast(value)); + } + ENTER_V8; + i::Handle result = i::Factory::NewNumber(value); + return Utils::IntegerToLocal(result); +} + + void V8::IgnoreOutOfMemoryException() { thread_local.set_ignore_out_of_memory(true); } diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index 1221f352cc..a28e1f0774 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -125,6 +125,15 @@ static inline v8::internal::Handle FromCData(T obj) { } +class ApiFunction { + public: + explicit ApiFunction(v8::internal::Address addr) : addr_(addr) { } + v8::internal::Address address() { return addr_; } + private: + v8::internal::Address addr_; +}; + + v8::Arguments::Arguments(v8::Local data, v8::Local holder, v8::Local callee, diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index 48cc09081d..d6046ec8db 100644 --- a/deps/v8/src/arm/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -245,6 +245,12 @@ Address Assembler::target_address_at(Address pc) { } +void Assembler::set_target_at(Address constant_pool_entry, + Address target) { + Memory::Address_at(constant_pool_entry) = target; +} + + void Assembler::set_target_address_at(Address pc, Address target) { Memory::Address_at(target_address_address_at(pc)) = target; // Intuitively, we would think it is necessary to flush the instruction cache diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index d1df08c571..d617c7e18e 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -437,6 +437,14 @@ class Assembler : public Malloced { INLINE(static Address target_address_at(Address pc)); INLINE(static void set_target_address_at(Address pc, Address target)); + // Modify the code target address in a constant pool entry. + inline static void set_target_at(Address constant_pool_entry, Address target); + + // Here we are patching the address in the constant pool, not the actual call + // instruction. The address in the constant pool is the same size as a + // pointer. + static const int kCallTargetSize = kPointerSize; + // Size of an instruction. static const int kInstrSize = sizeof(Instr); diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index d7afb37af1..6db554a77c 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -949,6 +949,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { const int kGlobalIndex = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; __ ldr(r2, FieldMemOperand(cp, kGlobalIndex)); + __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalContextOffset)); + __ ldr(r2, FieldMemOperand(r2, kGlobalIndex)); __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); __ bind(&patch_receiver); @@ -1107,6 +1109,8 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { const int kGlobalOffset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; __ ldr(r0, FieldMemOperand(cp, kGlobalOffset)); + __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset)); + __ ldr(r0, FieldMemOperand(r0, kGlobalOffset)); __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); // Push the receiver. diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 147c5e354c..3292bdcff2 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -1122,22 +1122,20 @@ void CodeGenerator::Branch(bool if_true, JumpTarget* target) { void CodeGenerator::CheckStack() { VirtualFrame::SpilledScope spilled_scope; - if (FLAG_check_stack) { - Comment cmnt(masm_, "[ check stack"); - __ LoadRoot(ip, Heap::kStackLimitRootIndex); - // Put the lr setup instruction in the delay slot. kInstrSize is added to - // the implicit 8 byte offset that always applies to operations with pc and - // gives a return address 12 bytes down. - masm_->add(lr, pc, Operand(Assembler::kInstrSize)); - masm_->cmp(sp, Operand(ip)); - StackCheckStub stub; - // Call the stub if lower. - masm_->mov(pc, - Operand(reinterpret_cast(stub.GetCode().location()), - RelocInfo::CODE_TARGET), - LeaveCC, - lo); - } + Comment cmnt(masm_, "[ check stack"); + __ LoadRoot(ip, Heap::kStackLimitRootIndex); + // Put the lr setup instruction in the delay slot. kInstrSize is added to + // the implicit 8 byte offset that always applies to operations with pc and + // gives a return address 12 bytes down. + masm_->add(lr, pc, Operand(Assembler::kInstrSize)); + masm_->cmp(sp, Operand(ip)); + StackCheckStub stub; + // Call the stub if lower. + masm_->mov(pc, + Operand(reinterpret_cast(stub.GetCode().location()), + RelocInfo::CODE_TARGET), + LeaveCC, + lo); } @@ -1172,9 +1170,9 @@ void CodeGenerator::VisitBlock(Block* node) { void CodeGenerator::DeclareGlobals(Handle pairs) { VirtualFrame::SpilledScope spilled_scope; + frame_->EmitPush(cp); __ mov(r0, Operand(pairs)); frame_->EmitPush(r0); - frame_->EmitPush(cp); __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); frame_->EmitPush(r0); frame_->CallRuntime(Runtime::kDeclareGlobals, 3); @@ -2255,12 +2253,10 @@ void CodeGenerator::InstantiateBoilerplate(Handle boilerplate) { VirtualFrame::SpilledScope spilled_scope; ASSERT(boilerplate->IsBoilerplate()); - // Push the boilerplate on the stack. - __ mov(r0, Operand(boilerplate)); - frame_->EmitPush(r0); - // Create a new closure. frame_->EmitPush(cp); + __ mov(r0, Operand(boilerplate)); + frame_->EmitPush(r0); frame_->CallRuntime(Runtime::kNewClosure, 2); frame_->EmitPush(r0); } @@ -5799,7 +5795,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_normal_exception, Label* throw_termination_exception, Label* throw_out_of_memory_exception, - StackFrame::Type frame_type, + ExitFrame::Mode mode, bool do_gc, bool always_allocate) { // r0: result parameter for PerformGC, if any @@ -5859,7 +5855,7 @@ void CEntryStub::GenerateCore(MacroAssembler* masm, // r0:r1: result // sp: stack pointer // fp: frame pointer - __ LeaveExitFrame(frame_type); + __ LeaveExitFrame(mode); // check if we should retry or throw exception Label retry; @@ -5905,12 +5901,12 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { // this by performing a garbage collection and retrying the // builtin once. - StackFrame::Type frame_type = is_debug_break - ? StackFrame::EXIT_DEBUG - : StackFrame::EXIT; + ExitFrame::Mode mode = is_debug_break + ? ExitFrame::MODE_DEBUG + : ExitFrame::MODE_NORMAL; // Enter the exit frame that transitions from JavaScript to C++. - __ EnterExitFrame(frame_type); + __ EnterExitFrame(mode); // r4: number of arguments (C callee-saved) // r5: pointer to builtin function (C callee-saved) @@ -5925,7 +5921,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - frame_type, + mode, false, false); @@ -5934,7 +5930,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - frame_type, + mode, true, false); @@ -5945,7 +5941,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { &throw_normal_exception, &throw_termination_exception, &throw_out_of_memory_exception, - frame_type, + mode, true, true); diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 7b50b01049..e0799508e0 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -242,7 +242,7 @@ class CodeGenerator: public AstVisitor { void LoadReference(Reference* ref); void UnloadReference(Reference* ref); - MemOperand ContextOperand(Register context, int index) const { + static MemOperand ContextOperand(Register context, int index) { return MemOperand(context, Context::SlotOffset(index)); } @@ -254,7 +254,7 @@ class CodeGenerator: public AstVisitor { JumpTarget* slow); // Expressions - MemOperand GlobalObject() const { + static MemOperand GlobalObject() { return ContextOperand(cp, Context::GLOBAL_INDEX); } @@ -330,10 +330,11 @@ class CodeGenerator: public AstVisitor { const InlineRuntimeLUT& new_entry, InlineRuntimeLUT* old_entry); + static Handle ComputeLazyCompile(int argc); Handle BuildBoilerplate(FunctionLiteral* node); void ProcessDeclarations(ZoneList* declarations); - Handle ComputeCallInitialize(int argc, InLoopFlag in_loop); + static Handle ComputeCallInitialize(int argc, InLoopFlag in_loop); // Declare global variables and functions in the given array of // name/value pairs. @@ -425,6 +426,8 @@ class CodeGenerator: public AstVisitor { friend class VirtualFrame; friend class JumpTarget; friend class Reference; + friend class FastCodeGenerator; + friend class CodeGenSelector; DISALLOW_COPY_AND_ASSIGN(CodeGenerator); }; diff --git a/deps/v8/src/arm/fast-codegen-arm.cc b/deps/v8/src/arm/fast-codegen-arm.cc index d2e620cfdf..21ee6d7e02 100644 --- a/deps/v8/src/arm/fast-codegen-arm.cc +++ b/deps/v8/src/arm/fast-codegen-arm.cc @@ -29,6 +29,7 @@ #include "codegen-inl.h" #include "fast-codegen.h" +#include "parser.h" namespace v8 { namespace internal { @@ -62,27 +63,32 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { if (locals_count > 0) { __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); } - if (FLAG_check_stack) { - __ LoadRoot(r2, Heap::kStackLimitRootIndex); - } + __ LoadRoot(r2, Heap::kStackLimitRootIndex); for (int i = 0; i < locals_count; i++) { __ push(ip); } } - if (FLAG_check_stack) { - // Put the lr setup instruction in the delay slot. The kInstrSize is - // added to the implicit 8 byte offset that always applies to operations - // with pc and gives a return address 12 bytes down. - Comment cmnt(masm_, "[ Stack check"); - __ add(lr, pc, Operand(Assembler::kInstrSize)); - __ cmp(sp, Operand(r2)); - StackCheckStub stub; - __ mov(pc, - Operand(reinterpret_cast(stub.GetCode().location()), - RelocInfo::CODE_TARGET), - LeaveCC, - lo); + // Check the stack for overflow or break request. + // Put the lr setup instruction in the delay slot. The kInstrSize is + // added to the implicit 8 byte offset that always applies to operations + // with pc and gives a return address 12 bytes down. + Comment cmnt(masm_, "[ Stack check"); + __ add(lr, pc, Operand(Assembler::kInstrSize)); + __ cmp(sp, Operand(r2)); + StackCheckStub stub; + __ mov(pc, + Operand(reinterpret_cast(stub.GetCode().location()), + RelocInfo::CODE_TARGET), + LeaveCC, + lo); + + { Comment cmnt(masm_, "[ Declarations"); + VisitDeclarations(fun->scope()->declarations()); + } + + if (FLAG_trace) { + __ CallRuntime(Runtime::kTraceEnter, 0); } { Comment cmnt(masm_, "[ Body"); @@ -94,6 +100,13 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { // body. __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); SetReturnPosition(fun); + if (FLAG_trace) { + // Push the return value on the stack as the parameter. + // Runtime::TraceExit returns its parameter in r0. + __ push(r0); + __ CallRuntime(Runtime::kTraceExit, 1); + } + __ RecordJSReturn(); __ mov(sp, fp); __ ldm(ia_w, sp, fp.bit() | lr.bit()); @@ -104,52 +117,311 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) { } -void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { - Comment cmnt(masm_, "[ ExpressionStatement"); - SetStatementPosition(stmt); - Visit(stmt->expression()); +void FastCodeGenerator::Move(Location destination, Slot* source) { + switch (destination.type()) { + case Location::NOWHERE: + break; + case Location::TEMP: + __ ldr(ip, MemOperand(fp, SlotOffset(source))); + __ push(ip); + break; + } +} + + +void FastCodeGenerator::Move(Location destination, Literal* expr) { + switch (destination.type()) { + case Location::NOWHERE: + break; + case Location::TEMP: + __ mov(ip, Operand(expr->handle())); + __ push(ip); + break; + } +} + + +void FastCodeGenerator::Move(Slot* destination, Location source) { + switch (source.type()) { + case Location::NOWHERE: + UNREACHABLE(); + case Location::TEMP: + __ pop(ip); + __ str(ip, MemOperand(fp, SlotOffset(destination))); + break; + } +} + + +void FastCodeGenerator::DropAndMove(Location destination, Register source) { + switch (destination.type()) { + case Location::NOWHERE: + __ pop(); + break; + case Location::TEMP: + __ str(source, MemOperand(sp)); + break; + } +} + + +void FastCodeGenerator::DeclareGlobals(Handle pairs) { + // Call the runtime to declare the globals. + // The context is the first argument. + __ mov(r1, Operand(pairs)); + __ mov(r0, Operand(Smi::FromInt(is_eval_ ? 1 : 0))); + __ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit()); + __ CallRuntime(Runtime::kDeclareGlobals, 3); + // Return value is ignored. } void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { Comment cmnt(masm_, "[ ReturnStatement"); SetStatementPosition(stmt); - Visit(stmt->expression()); - __ pop(r0); + Expression* expr = stmt->expression(); + // Complete the statement based on the type of the subexpression. + if (expr->AsLiteral() != NULL) { + __ mov(r0, Operand(expr->AsLiteral()->handle())); + } else { + Visit(expr); + Move(r0, expr->location()); + } + + if (FLAG_trace) { + __ push(r0); + __ CallRuntime(Runtime::kTraceExit, 1); + } + __ RecordJSReturn(); __ mov(sp, fp); __ ldm(ia_w, sp, fp.bit() | lr.bit()); - int num_parameters = function_->scope()->num_parameters(); + int num_parameters = function_->scope()->num_parameters(); __ add(sp, sp, Operand((num_parameters + 1) * kPointerSize)); __ Jump(lr); } +void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { + Comment cmnt(masm_, "[ FunctionLiteral"); + + // Build the function boilerplate and instantiate it. + Handle boilerplate = BuildBoilerplate(expr); + if (HasStackOverflow()) return; + + ASSERT(boilerplate->IsBoilerplate()); + + // Create a new closure. + __ mov(r0, Operand(boilerplate)); + __ stm(db_w, sp, cp.bit() | r0.bit()); + __ CallRuntime(Runtime::kNewClosure, 2); + Move(expr->location(), r0); +} + + void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { Comment cmnt(masm_, "[ VariableProxy"); Expression* rewrite = expr->var()->rewrite(); - ASSERT(rewrite != NULL); + if (rewrite == NULL) { + Comment cmnt(masm_, "Global variable"); + // Use inline caching. Variable name is passed in r2 and the global + // object on the stack. + __ ldr(ip, CodeGenerator::GlobalObject()); + __ push(ip); + __ mov(r2, Operand(expr->name())); + Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + DropAndMove(expr->location(), r0); + } else { + Comment cmnt(masm_, "Stack slot"); + Move(expr->location(), rewrite->AsSlot()); + } +} - Slot* slot = rewrite->AsSlot(); - ASSERT(slot != NULL); - { Comment cmnt(masm_, "[ Slot"); - if (expr->location().is_temporary()) { - __ ldr(ip, MemOperand(fp, SlotOffset(slot))); - __ push(ip); - } else { - ASSERT(expr->location().is_nowhere()); + +void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { + Comment cmnt(masm_, "[ ObjectLiteral"); + Label boilerplate_exists; + __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); + // r2 = literal array (0). + __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); + int literal_offset = + FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; + __ ldr(r0, FieldMemOperand(r2, literal_offset)); + // Check whether we need to materialize the object literal boilerplate. + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + __ cmp(r0, Operand(ip)); + __ b(ne, &boilerplate_exists); + // Create boilerplate if it does not exist. + // r1 = literal index (1). + __ mov(r1, Operand(Smi::FromInt(expr->literal_index()))); + // r0 = constant properties (2). + __ mov(r0, Operand(expr->constant_properties())); + __ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit()); + __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); + __ bind(&boilerplate_exists); + // r0 contains boilerplate. + // Clone boilerplate. + __ push(r0); + if (expr->depth() > 1) { + __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); + } else { + __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); + } + + // If result_saved == true: the result is saved on top of the stack. + // If result_saved == false: the result is in eax. + bool result_saved = false; + + for (int i = 0; i < expr->properties()->length(); i++) { + ObjectLiteral::Property* property = expr->properties()->at(i); + if (property->IsCompileTimeValue()) continue; + + Literal* key = property->key(); + Expression* value = property->value(); + if (!result_saved) { + __ push(r0); // Save result on stack + result_saved = true; } + switch (property->kind()) { + case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through + ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); + case ObjectLiteral::Property::COMPUTED: // fall through + case ObjectLiteral::Property::PROTOTYPE: + __ push(r0); + Visit(key); + ASSERT(key->location().is_temporary()); + Visit(value); + ASSERT(value->location().is_temporary()); + __ CallRuntime(Runtime::kSetProperty, 3); + __ ldr(r0, MemOperand(sp)); // Restore result into r0 + break; + case ObjectLiteral::Property::SETTER: // fall through + case ObjectLiteral::Property::GETTER: + __ push(r0); + Visit(key); + ASSERT(key->location().is_temporary()); + __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ? + Smi::FromInt(1) : + Smi::FromInt(0))); + __ push(r1); + Visit(value); + ASSERT(value->location().is_temporary()); + __ CallRuntime(Runtime::kDefineAccessor, 4); + __ ldr(r0, MemOperand(sp)); // Restore result into r0 + break; + default: UNREACHABLE(); + } + } + switch (expr->location().type()) { + case Location::NOWHERE: + if (result_saved) __ pop(); + break; + case Location::TEMP: + if (!result_saved) __ push(r0); + break; } } -void FastCodeGenerator::VisitLiteral(Literal* expr) { - Comment cmnt(masm_, "[ Literal"); - if (expr->location().is_temporary()) { - __ mov(ip, Operand(expr->handle())); - __ push(ip); +void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { + Comment cmnt(masm_, "[ RegExp Literal"); + Label done; + // Registers will be used as follows: + // r4 = JS function, literals array + // r3 = literal index + // r2 = RegExp pattern + // r1 = RegExp flags + // r0 = temp + return value (RegExp literal) + __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); + __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); + int literal_offset = + FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; + __ ldr(r0, FieldMemOperand(r4, literal_offset)); + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + __ cmp(r0, ip); + __ b(ne, &done); + __ mov(r3, Operand(Smi::FromInt(expr->literal_index()))); + __ mov(r2, Operand(expr->pattern())); + __ mov(r1, Operand(expr->flags())); + __ stm(db_w, sp, r4.bit() | r3.bit() | r2.bit() | r1.bit()); + __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); + __ bind(&done); + Move(expr->location(), r0); +} + + +void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { + Comment cmnt(masm_, "[ ArrayLiteral"); + Label make_clone; + + // Fetch the function's literals array. + __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); + __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); + // Check if the literal's boilerplate has been instantiated. + int offset = + FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); + __ ldr(r0, FieldMemOperand(r3, offset)); + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); + __ cmp(r0, ip); + __ b(&make_clone, ne); + + // Instantiate the boilerplate. + __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); + __ mov(r1, Operand(expr->literals())); + __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit()); + __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3); + + __ bind(&make_clone); + // Clone the boilerplate. + __ push(r0); + if (expr->depth() > 1) { + __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); } else { - ASSERT(expr->location().is_nowhere()); + __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); + } + + bool result_saved = false; // Is the result saved to the stack? + + // Emit code to evaluate all the non-constant subexpressions and to store + // them into the newly cloned array. + ZoneList* subexprs = expr->values(); + for (int i = 0, len = subexprs->length(); i < len; i++) { + Expression* subexpr = subexprs->at(i); + // If the subexpression is a literal or a simple materialized literal it + // is already set in the cloned array. + if (subexpr->AsLiteral() != NULL || + CompileTimeValue::IsCompileTimeValue(subexpr)) { + continue; + } + + if (!result_saved) { + __ push(r0); + result_saved = true; + } + Visit(subexpr); + ASSERT(subexpr->location().is_temporary()); + + // Store the subexpression value in the array's elements. + __ pop(r0); // Subexpression value. + __ ldr(r1, MemOperand(sp)); // Copy of array literal. + __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); + int offset = FixedArray::kHeaderSize + (i * kPointerSize); + __ str(r0, FieldMemOperand(r1, offset)); + + // Update the write barrier for the array store with r0 as the scratch + // register. + __ mov(r2, Operand(offset)); + __ RecordWrite(r1, r2, r0); + } + + switch (expr->location().type()) { + case Location::NOWHERE: + if (result_saved) __ pop(); + break; + case Location::TEMP: + if (!result_saved) __ push(r0); + break; } } @@ -158,19 +430,239 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { Comment cmnt(masm_, "[ Assignment"); ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); - Visit(expr->value()); - + // Left-hand side can only be a global or a (parameter or local) slot. Variable* var = expr->target()->AsVariableProxy()->AsVariable(); - ASSERT(var != NULL && var->slot() != NULL); + ASSERT(var != NULL); + ASSERT(var->is_global() || var->slot() != NULL); - if (expr->location().is_temporary()) { - __ ldr(ip, MemOperand(sp)); + Expression* rhs = expr->value(); + Location destination = expr->location(); + if (var->is_global()) { + // Assignment to a global variable, use inline caching. Right-hand-side + // value is passed in r0, variable name in r2, and the global object on + // the stack. + + // Code for the right-hand-side expression depends on its type. + if (rhs->AsLiteral() != NULL) { + __ mov(r0, Operand(rhs->AsLiteral()->handle())); + } else { + ASSERT(rhs->location().is_temporary()); + Visit(rhs); + __ pop(r0); + } + __ mov(r2, Operand(var->name())); + __ ldr(ip, CodeGenerator::GlobalObject()); + __ push(ip); + Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + // Overwrite the global object on the stack with the result if needed. + DropAndMove(expr->location(), r0); } else { - ASSERT(expr->location().is_nowhere()); - __ pop(ip); + // Local or parameter assignment. + + // Code for the right-hand side expression depends on its type. + if (rhs->AsLiteral() != NULL) { + // Two cases: 'temp <- (var = constant)', or 'var = constant' with a + // discarded result. Always perform the assignment. + __ mov(ip, Operand(rhs->AsLiteral()->handle())); + __ str(ip, MemOperand(fp, SlotOffset(var->slot()))); + Move(expr->location(), ip); + } else { + ASSERT(rhs->location().is_temporary()); + Visit(rhs); + // Load right-hand side into ip. + switch (expr->location().type()) { + case Location::NOWHERE: + // Case 'var = temp'. Discard right-hand-side temporary. + __ pop(ip); + break; + case Location::TEMP: + // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side + // temporary on the stack. + __ ldr(ip, MemOperand(sp)); + break; + } + // Do the slot assignment. + __ str(ip, MemOperand(fp, SlotOffset(var->slot()))); + } + } +} + + +void FastCodeGenerator::VisitProperty(Property* expr) { + Comment cmnt(masm_, "[ Property"); + Expression* key = expr->key(); + uint32_t dummy; + + // Record the source position for the property load. + SetSourcePosition(expr->position()); + + // Evaluate receiver. + Visit(expr->obj()); + + if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() && + !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) { + // Do a NAMED property load. + // The IC expects the property name in ecx and the receiver on the stack. + __ mov(r2, Operand(key->AsLiteral()->handle())); + Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + // By emitting a nop we make sure that we do not have a "test eax,..." + // instruction after the call it is treated specially by the LoadIC code. + __ nop(); + } else { + // Do a KEYED property load. + Visit(expr->key()); + Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + // By emitting a nop we make sure that we do not have a "test eax,..." + // instruction after the call it is treated specially by the LoadIC code. + __ nop(); + // Drop key and receiver left on the stack by IC. + __ pop(); + } + switch (expr->location().type()) { + case Location::TEMP: + __ str(r0, MemOperand(sp)); + break; + case Location::NOWHERE: + __ pop(); + } +} + + +void FastCodeGenerator::VisitCall(Call* expr) { + Comment cmnt(masm_, "[ Call"); + Expression* fun = expr->expression(); + ZoneList* args = expr->arguments(); + Variable* var = fun->AsVariableProxy()->AsVariable(); + ASSERT(var != NULL && !var->is_this() && var->is_global()); + ASSERT(!var->is_possibly_eval()); + + __ mov(r1, Operand(var->name())); + // Push global object as receiver. + __ ldr(r0, CodeGenerator::GlobalObject()); + __ stm(db_w, sp, r1.bit() | r0.bit()); + int arg_count = args->length(); + for (int i = 0; i < arg_count; i++) { + Visit(args->at(i)); + ASSERT(args->at(i)->location().is_temporary()); } - __ str(ip, MemOperand(fp, SlotOffset(var->slot()))); + // Record source position for debugger + SetSourcePosition(expr->position()); + // Call the IC initialization code. + Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, + NOT_IN_LOOP); + __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + // Restore context register. + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + DropAndMove(expr->location(), r0); } +void FastCodeGenerator::VisitCallNew(CallNew* node) { + Comment cmnt(masm_, "[ CallNew"); + // According to ECMA-262, section 11.2.2, page 44, the function + // expression in new calls must be evaluated before the + // arguments. + // Push function on the stack. + Visit(node->expression()); + ASSERT(node->expression()->location().is_temporary()); + + // Push global object (receiver). + __ ldr(r0, CodeGenerator::GlobalObject()); + __ push(r0); + // Push the arguments ("left-to-right") on the stack. + ZoneList* args = node->arguments(); + int arg_count = args->length(); + for (int i = 0; i < arg_count; i++) { + Visit(args->at(i)); + ASSERT(args->at(i)->location().is_temporary()); + // If location is temporary, it is already on the stack, + // so nothing to do here. + } + + // Call the construct call builtin that handles allocation and + // constructor invocation. + SetSourcePosition(node->position()); + + // Load function, arg_count into r1 and r0. + __ mov(r0, Operand(arg_count)); + // Function is in esp[arg_count + 1]. + __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); + + Handle construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); + __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); + + // Replace function on TOS with result in r0, or pop it. + DropAndMove(node->location(), r0); +} + + +void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { + Comment cmnt(masm_, "[ CallRuntime"); + ZoneList* args = expr->arguments(); + Runtime::Function* function = expr->function(); + + ASSERT(function != NULL); + + // Push the arguments ("left-to-right"). + int arg_count = args->length(); + for (int i = 0; i < arg_count; i++) { + Visit(args->at(i)); + ASSERT(args->at(i)->location().is_temporary()); + } + + __ CallRuntime(function, arg_count); + Move(expr->location(), r0); +} + + +void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { + // Compile a short-circuited boolean or operation in a non-test + // context. + ASSERT(expr->op() == Token::OR); + // Compile (e0 || e1) as if it were + // (let (temp = e0) temp ? temp : e1). + + Label done; + Location destination = expr->location(); + Expression* left = expr->left(); + Expression* right = expr->right(); + + // Call the runtime to find the boolean value of the left-hand + // subexpression. Duplicate the value if it may be needed as the final + // result. + if (left->AsLiteral() != NULL) { + __ mov(r0, Operand(left->AsLiteral()->handle())); + __ push(r0); + if (destination.is_temporary()) __ push(r0); + } else { + Visit(left); + ASSERT(left->location().is_temporary()); + if (destination.is_temporary()) { + __ ldr(r0, MemOperand(sp)); + __ push(r0); + } + } + // The left-hand value is in on top of the stack. It is duplicated on the + // stack iff the destination location is temporary. + __ CallRuntime(Runtime::kToBool, 1); + __ LoadRoot(ip, Heap::kTrueValueRootIndex); + __ cmp(r0, ip); + __ b(eq, &done); + + // Discard the left-hand value if present on the stack. + if (destination.is_temporary()) __ pop(); + // Save or discard the right-hand value as needed. + if (right->AsLiteral() != NULL) { + Move(destination, right->AsLiteral()); + } else { + Visit(right); + Move(destination, right->location()); + } + + __ bind(&done); +} + } } // namespace v8::internal diff --git a/deps/v8/src/arm/frames-arm.cc b/deps/v8/src/arm/frames-arm.cc index 6fde4b73c0..b0fa13a5a1 100644 --- a/deps/v8/src/arm/frames-arm.cc +++ b/deps/v8/src/arm/frames-arm.cc @@ -54,23 +54,24 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) { if (fp == 0) return NONE; // Compute frame type and stack pointer. Address sp = fp + ExitFrameConstants::kSPDisplacement; - Type type; - if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) { - type = EXIT_DEBUG; + const int offset = ExitFrameConstants::kCodeOffset; + Object* code = Memory::Object_at(fp + offset); + bool is_debug_exit = code->IsSmi(); + if (is_debug_exit) { sp -= kNumJSCallerSaved * kPointerSize; - } else { - type = EXIT; } // Fill in the state. state->sp = sp; state->fp = fp; state->pc_address = reinterpret_cast(sp - 1 * kPointerSize); - return type; + return EXIT; } void ExitFrame::Iterate(ObjectVisitor* v) const { - // Do nothing + v->VisitPointer(&code_slot()); + // The arguments are traversed as part of the expression stack of + // the calling frame. } diff --git a/deps/v8/src/arm/frames-arm.h b/deps/v8/src/arm/frames-arm.h index 0874c09274..4924c1aeb9 100644 --- a/deps/v8/src/arm/frames-arm.h +++ b/deps/v8/src/arm/frames-arm.h @@ -100,7 +100,7 @@ class ExitFrameConstants : public AllStatic { static const int kSPDisplacement = -1 * kPointerSize; // The debug marker is just above the frame pointer. - static const int kDebugMarkOffset = -1 * kPointerSize; + static const int kCodeOffset = -1 * kPointerSize; static const int kSavedRegistersOffset = 0 * kPointerSize; diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index d230b4546f..ba8364545e 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -615,6 +615,13 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { } +void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, + ExternalArrayType array_type) { + // TODO(476): port specialized code. + GenerateGeneric(masm); +} + + void KeyedStoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) { // ---------- S t a t e -------------- @@ -748,6 +755,13 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { } +void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, + ExternalArrayType array_type) { + // TODO(476): port specialized code. + GenerateGeneric(masm); +} + + void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) { // ---------- S t a t e -------------- // -- r0 : value diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 45c6540eeb..dc73bad93f 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -274,9 +274,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { } -void MacroAssembler::EnterExitFrame(StackFrame::Type type) { - ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG); - +void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode) { // Compute the argv pointer and keep it in a callee-saved register. // r0 is argc. add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); @@ -298,8 +296,11 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) { stm(db_w, sp, fp.bit() | ip.bit() | lr.bit()); mov(fp, Operand(sp)); // setup new frame pointer - // Push debug marker. - mov(ip, Operand(type == StackFrame::EXIT_DEBUG ? 1 : 0)); + if (mode == ExitFrame::MODE_DEBUG) { + mov(ip, Operand(Smi::FromInt(0))); + } else { + mov(ip, Operand(CodeObject())); + } push(ip); // Save the frame pointer and the context in top. @@ -316,7 +317,7 @@ void MacroAssembler::EnterExitFrame(StackFrame::Type type) { #ifdef ENABLE_DEBUGGER_SUPPORT // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. - if (type == StackFrame::EXIT_DEBUG) { + if (mode == ExitFrame::MODE_DEBUG) { // Use sp as base to push. CopyRegistersFromMemoryToStack(sp, kJSCallerSaved); } @@ -348,14 +349,14 @@ void MacroAssembler::AlignStack(int offset) { } -void MacroAssembler::LeaveExitFrame(StackFrame::Type type) { +void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) { #ifdef ENABLE_DEBUGGER_SUPPORT // Restore the memory copy of the registers by digging them out from // the stack. This is needed to allow nested break points. - if (type == StackFrame::EXIT_DEBUG) { + if (mode == ExitFrame::MODE_DEBUG) { // This code intentionally clobbers r2 and r3. const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize; - const int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize; + const int kOffset = ExitFrameConstants::kCodeOffset - kCallerSavedSize; add(r3, fp, Operand(kOffset)); CopyRegistersFromStackToMemory(r3, r2, kJSCallerSaved); } diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index e37bb5e1c2..6dc2b7ae89 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -87,14 +87,14 @@ class MacroAssembler: public Assembler { void EnterConstructFrame() { EnterFrame(StackFrame::CONSTRUCT); } void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); } - // Enter specific kind of exit frame; either EXIT or - // EXIT_DEBUG. Expects the number of arguments in register r0 and + // Enter specific kind of exit frame; either normal or debug mode. + // Expects the number of arguments in register r0 and // the builtin function to call in register r1. Exits with argc in // r4, argv in r6, and and the builtin function to call in r5. - void EnterExitFrame(StackFrame::Type type); + void EnterExitFrame(ExitFrame::Mode mode); // Leave the current exit frame. Expects the return value in r0. - void LeaveExitFrame(StackFrame::Type type); + void LeaveExitFrame(ExitFrame::Mode mode); // Align the stack by optionally pushing a Smi zero. void AlignStack(int offset); diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index 2e75a61a84..bd50428d8b 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -29,6 +29,7 @@ #include "unicode.h" #include "log.h" #include "ast.h" +#include "code-stubs.h" #include "regexp-stack.h" #include "macro-assembler.h" #include "regexp-macro-assembler.h" @@ -1099,14 +1100,12 @@ void RegExpMacroAssemblerARM::CheckPreemption() { void RegExpMacroAssemblerARM::CheckStackLimit() { - if (FLAG_check_stack) { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit(); - __ mov(r0, Operand(stack_limit)); - __ ldr(r0, MemOperand(r0)); - __ cmp(backtrack_stackpointer(), Operand(r0)); - SafeCall(&stack_overflow_label_, ls); - } + ExternalReference stack_limit = + ExternalReference::address_of_regexp_stack_limit(); + __ mov(r0, Operand(stack_limit)); + __ ldr(r0, MemOperand(r0)); + __ cmp(backtrack_stackpointer(), Operand(r0)); + SafeCall(&stack_overflow_label_, ls); } diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.h b/deps/v8/src/arm/regexp-macro-assembler-arm.h index 0711ac19f7..f70bc05544 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.h +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.h @@ -260,6 +260,21 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { }; +// Enter C code from generated RegExp code in a way that allows +// the C code to fix the return address in case of a GC. +// Currently only needed on ARM. +class RegExpCEntryStub: public CodeStub { + public: + RegExpCEntryStub() {} + virtual ~RegExpCEntryStub() {} + void Generate(MacroAssembler* masm); + + private: + Major MajorKey() { return RegExpCEntry; } + int MinorKey() { return 0; } + const char* GetName() { return "RegExpCEntryStub"; } +}; + #endif // V8_NATIVE_REGEXP diff --git a/deps/v8/src/arm/virtual-frame-arm.cc b/deps/v8/src/arm/virtual-frame-arm.cc index 2d5b1406c2..47ecb96360 100644 --- a/deps/v8/src/arm/virtual-frame-arm.cc +++ b/deps/v8/src/arm/virtual-frame-arm.cc @@ -146,29 +146,27 @@ void VirtualFrame::AllocateStackSlots() { // Initialize stack slots with 'undefined' value. __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); } - if (FLAG_check_stack) { - __ LoadRoot(r2, Heap::kStackLimitRootIndex); - } + __ LoadRoot(r2, Heap::kStackLimitRootIndex); for (int i = 0; i < count; i++) { __ push(ip); } - if (FLAG_check_stack) { - // Put the lr setup instruction in the delay slot. The kInstrSize is added - // to the implicit 8 byte offset that always applies to operations with pc - // and gives a return address 12 bytes down. - masm()->add(lr, pc, Operand(Assembler::kInstrSize)); - masm()->cmp(sp, Operand(r2)); - StackCheckStub stub; - // Call the stub if lower. - masm()->mov(pc, - Operand(reinterpret_cast(stub.GetCode().location()), - RelocInfo::CODE_TARGET), - LeaveCC, - lo); - } + // Check the stack for overflow or a break request. + // Put the lr setup instruction in the delay slot. The kInstrSize is added + // to the implicit 8 byte offset that always applies to operations with pc + // and gives a return address 12 bytes down. + masm()->add(lr, pc, Operand(Assembler::kInstrSize)); + masm()->cmp(sp, Operand(r2)); + StackCheckStub stub; + // Call the stub if lower. + masm()->mov(pc, + Operand(reinterpret_cast(stub.GetCode().location()), + RelocInfo::CODE_TARGET), + LeaveCC, + lo); } + void VirtualFrame::SaveContextRegister() { UNIMPLEMENTED(); } @@ -255,7 +253,7 @@ void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, void VirtualFrame::RawCallCodeObject(Handle code, - RelocInfo::Mode rmode) { + RelocInfo::Mode rmode) { ASSERT(cgen()->HasValidEntryRegisters()); __ Call(code, rmode); } diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 34595f83ff..34346a9105 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -522,6 +522,10 @@ ExternalReference::ExternalReference(Builtins::CFunctionId id) : address_(Redirect(Builtins::c_function_address(id))) {} +ExternalReference::ExternalReference(ApiFunction* fun) + : address_(Redirect(fun->address())) {} + + ExternalReference::ExternalReference(Builtins::Name name) : address_(Builtins::builtin_address(name)) {} @@ -608,6 +612,27 @@ ExternalReference ExternalReference::new_space_allocation_limit_address() { return ExternalReference(Heap::NewSpaceAllocationLimitAddress()); } + +ExternalReference ExternalReference::handle_scope_extensions_address() { + return ExternalReference(HandleScope::current_extensions_address()); +} + + +ExternalReference ExternalReference::handle_scope_next_address() { + return ExternalReference(HandleScope::current_next_address()); +} + + +ExternalReference ExternalReference::handle_scope_limit_address() { + return ExternalReference(HandleScope::current_limit_address()); +} + + +ExternalReference ExternalReference::scheduled_exception_address() { + return ExternalReference(Top::scheduled_exception_address()); +} + + #ifdef V8_NATIVE_REGEXP ExternalReference ExternalReference::re_check_stack_guard_state() { diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 21a66dd501..311dadd53c 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -373,6 +373,8 @@ class ExternalReference BASE_EMBEDDED { public: explicit ExternalReference(Builtins::CFunctionId id); + explicit ExternalReference(ApiFunction* ptr); + explicit ExternalReference(Builtins::Name name); explicit ExternalReference(Runtime::FunctionId id); @@ -422,6 +424,12 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference double_fp_operation(Token::Value operation); static ExternalReference compare_doubles(); + static ExternalReference handle_scope_extensions_address(); + static ExternalReference handle_scope_next_address(); + static ExternalReference handle_scope_limit_address(); + + static ExternalReference scheduled_exception_address(); + Address address() const {return reinterpret_cast
(address_);} #ifdef ENABLE_DEBUGGER_SUPPORT diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index f6864b82e0..90b5ed68ac 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -28,6 +28,7 @@ #include "v8.h" #include "ast.h" +#include "parser.h" #include "scopes.h" #include "string-stream.h" @@ -138,6 +139,13 @@ ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) { } +bool ObjectLiteral::Property::IsCompileTimeValue() { + return kind_ == CONSTANT || + (kind_ == MATERIALIZED_LITERAL && + CompileTimeValue::IsCompileTimeValue(value_)); +} + + bool ObjectLiteral::IsValidJSON() { int length = properties()->length(); for (int i = 0; i < length; i++) { diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index 42154f61c2..9b7d9ddb05 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -747,6 +747,8 @@ class ObjectLiteral: public MaterializedLiteral { Expression* value() { return value_; } Kind kind() { return kind_; } + bool IsCompileTimeValue(); + private: Literal* key_; Expression* value_; diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 43aa1a3b89..3436b505dc 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -316,8 +316,11 @@ Genesis* Genesis::current_ = NULL; void Bootstrapper::Iterate(ObjectVisitor* v) { natives_cache.Iterate(v); + v->Synchronize("NativesCache"); extensions_cache.Iterate(v); + v->Synchronize("Extensions"); PendingFixups::Iterate(v); + v->Synchronize("PendingFixups"); } diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index afb54275e6..fa1b34e655 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -538,6 +538,44 @@ static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) { } +static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) { + KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray); +} + + +static void Generate_KeyedLoadIC_ExternalUnsignedByteArray( + MacroAssembler* masm) { + KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray); +} + + +static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) { + KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray); +} + + +static void Generate_KeyedLoadIC_ExternalUnsignedShortArray( + MacroAssembler* masm) { + KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray); +} + + +static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) { + KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray); +} + + +static void Generate_KeyedLoadIC_ExternalUnsignedIntArray( + MacroAssembler* masm) { + KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray); +} + + +static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) { + KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray); +} + + static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) { KeyedLoadIC::GeneratePreMonomorphic(masm); } @@ -567,6 +605,44 @@ static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) { } +static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) { + KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray); +} + + +static void Generate_KeyedStoreIC_ExternalUnsignedByteArray( + MacroAssembler* masm) { + KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray); +} + + +static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) { + KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray); +} + + +static void Generate_KeyedStoreIC_ExternalUnsignedShortArray( + MacroAssembler* masm) { + KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray); +} + + +static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) { + KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray); +} + + +static void Generate_KeyedStoreIC_ExternalUnsignedIntArray( + MacroAssembler* masm) { + KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray); +} + + +static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) { + KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray); +} + + static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) { KeyedStoreIC::GenerateExtendStorage(masm); } diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h index 141d5b7a58..bc32c49208 100644 --- a/deps/v8/src/builtins.h +++ b/deps/v8/src/builtins.h @@ -48,44 +48,58 @@ namespace internal { // Define list of builtins implemented in assembly. -#define BUILTIN_LIST_A(V) \ - V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \ - V(JSConstructCall, BUILTIN, UNINITIALIZED) \ - V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \ - V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \ - V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \ - \ - V(LoadIC_Miss, BUILTIN, UNINITIALIZED) \ - V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \ - V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \ - V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED) \ - \ - V(StoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \ - V(KeyedStoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \ - \ - V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED) \ - V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \ - V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \ - V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \ - V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \ - V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \ - V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \ - \ - V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \ - V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \ - V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \ - \ - V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \ - V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \ - \ - V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \ - V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \ - \ - /* Uses KeyedLoadIC_Initialize; must be after in list. */ \ - V(FunctionCall, BUILTIN, UNINITIALIZED) \ - V(FunctionApply, BUILTIN, UNINITIALIZED) \ - \ - V(ArrayCode, BUILTIN, UNINITIALIZED) \ +#define BUILTIN_LIST_A(V) \ + V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \ + V(JSConstructCall, BUILTIN, UNINITIALIZED) \ + V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED) \ + V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \ + V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \ + \ + V(LoadIC_Miss, BUILTIN, UNINITIALIZED) \ + V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \ + V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \ + V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED) \ + \ + V(StoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \ + V(KeyedStoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \ + \ + V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED) \ + V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \ + V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \ + V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \ + V(LoadIC_StringLength, LOAD_IC, MONOMORPHIC) \ + V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \ + V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \ + \ + V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \ + V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \ + V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \ + V(KeyedLoadIC_ExternalByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \ + V(KeyedLoadIC_ExternalUnsignedByteArray, KEYED_LOAD_IC, MEGAMORPHIC) \ + V(KeyedLoadIC_ExternalShortArray, KEYED_LOAD_IC, MEGAMORPHIC) \ + V(KeyedLoadIC_ExternalUnsignedShortArray, KEYED_LOAD_IC, MEGAMORPHIC) \ + V(KeyedLoadIC_ExternalIntArray, KEYED_LOAD_IC, MEGAMORPHIC) \ + V(KeyedLoadIC_ExternalUnsignedIntArray, KEYED_LOAD_IC, MEGAMORPHIC) \ + V(KeyedLoadIC_ExternalFloatArray, KEYED_LOAD_IC, MEGAMORPHIC) \ + \ + V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \ + V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \ + \ + V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \ + V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \ + V(KeyedStoreIC_ExternalByteArray, KEYED_STORE_IC, MEGAMORPHIC) \ + V(KeyedStoreIC_ExternalUnsignedByteArray, KEYED_STORE_IC, MEGAMORPHIC) \ + V(KeyedStoreIC_ExternalShortArray, KEYED_STORE_IC, MEGAMORPHIC) \ + V(KeyedStoreIC_ExternalUnsignedShortArray, KEYED_STORE_IC, MEGAMORPHIC) \ + V(KeyedStoreIC_ExternalIntArray, KEYED_STORE_IC, MEGAMORPHIC) \ + V(KeyedStoreIC_ExternalUnsignedIntArray, KEYED_STORE_IC, MEGAMORPHIC) \ + V(KeyedStoreIC_ExternalFloatArray, KEYED_STORE_IC, MEGAMORPHIC) \ + \ + /* Uses KeyedLoadIC_Initialize; must be after in list. */ \ + V(FunctionCall, BUILTIN, UNINITIALIZED) \ + V(FunctionApply, BUILTIN, UNINITIALIZED) \ + \ + V(ArrayCode, BUILTIN, UNINITIALIZED) \ V(ArrayConstructCode, BUILTIN, UNINITIALIZED) #ifdef ENABLE_DEBUGGER_SUPPORT diff --git a/deps/v8/src/code-stubs.cc b/deps/v8/src/code-stubs.cc index 586c9480c4..7a2f859459 100644 --- a/deps/v8/src/code-stubs.cc +++ b/deps/v8/src/code-stubs.cc @@ -36,10 +36,27 @@ namespace v8 { namespace internal { Handle CodeStub::GetCode() { - uint32_t key = GetKey(); - int index = Heap::code_stubs()->FindEntry(key); - if (index == NumberDictionary::kNotFound) { - HandleScope scope; + bool custom_cache = has_custom_cache(); + + int index = 0; + uint32_t key = 0; + if (custom_cache) { + Code* cached; + if (GetCustomCache(&cached)) { + return Handle(cached); + } else { + index = NumberDictionary::kNotFound; + } + } else { + key = GetKey(); + index = Heap::code_stubs()->FindEntry(key); + if (index != NumberDictionary::kNotFound) + return Handle(Code::cast(Heap::code_stubs()->ValueAt(index))); + } + + Code* result; + { + v8::HandleScope scope; // Update the static counter each time a new code stub is generated. Counters::code_stubs.Increment(); @@ -79,63 +96,29 @@ Handle CodeStub::GetCode() { } #endif - // Update the dictionary and the root in Heap. - Handle dict = - Factory::DictionaryAtNumberPut( - Handle(Heap::code_stubs()), - key, - code); - Heap::public_set_code_stubs(*dict); - index = Heap::code_stubs()->FindEntry(key); + if (custom_cache) { + SetCustomCache(*code); + } else { + // Update the dictionary and the root in Heap. + Handle dict = + Factory::DictionaryAtNumberPut( + Handle(Heap::code_stubs()), + key, + code); + Heap::public_set_code_stubs(*dict); + } + result = *code; } - ASSERT(index != NumberDictionary::kNotFound); - return Handle(Code::cast(Heap::code_stubs()->ValueAt(index))); + return Handle(result); } const char* CodeStub::MajorName(CodeStub::Major major_key) { switch (major_key) { - case CallFunction: - return "CallFunction"; - case GenericBinaryOp: - return "GenericBinaryOp"; - case SmiOp: - return "SmiOp"; - case Compare: - return "Compare"; - case RecordWrite: - return "RecordWrite"; - case StackCheck: - return "StackCheck"; - case UnarySub: - return "UnarySub"; - case RevertToNumber: - return "RevertToNumber"; - case ToBoolean: - return "ToBoolean"; - case Instanceof: - return "Instanceof"; - case CounterOp: - return "CounterOp"; - case ArgumentsAccess: - return "ArgumentsAccess"; - case Runtime: - return "Runtime"; - case CEntry: - return "CEntry"; - case JSEntry: - return "JSEntry"; - case GetProperty: - return "GetProperty"; - case SetProperty: - return "SetProperty"; - case InvokeBuiltin: - return "InvokeBuiltin"; - case ConvertToDouble: - return "ConvertToDouble"; - case WriteInt32ToHeapNumber: - return "WriteInt32ToHeapNumber"; +#define DEF_CASE(name) case name: return #name; + CODE_STUB_LIST_ALL(DEF_CASE) +#undef DEF_CASE default: UNREACHABLE(); return NULL; diff --git a/deps/v8/src/code-stubs.h b/deps/v8/src/code-stubs.h index 91d951f2f6..63461bc0c0 100644 --- a/deps/v8/src/code-stubs.h +++ b/deps/v8/src/code-stubs.h @@ -31,32 +31,51 @@ namespace v8 { namespace internal { +// List of code stubs used on all platforms. The order in this list is important +// as only the stubs up to and including RecordWrite allows nested stub calls. +#define CODE_STUB_LIST_ALL(V) \ + V(CallFunction) \ + V(GenericBinaryOp) \ + V(SmiOp) \ + V(Compare) \ + V(RecordWrite) \ + V(ConvertToDouble) \ + V(WriteInt32ToHeapNumber) \ + V(StackCheck) \ + V(UnarySub) \ + V(RevertToNumber) \ + V(ToBoolean) \ + V(Instanceof) \ + V(CounterOp) \ + V(ArgumentsAccess) \ + V(Runtime) \ + V(CEntry) \ + V(JSEntry) + +// List of code stubs only used on ARM platforms. +#ifdef V8_TARGET_ARCH_ARM +#define CODE_STUB_LIST_ARM(V) \ + V(GetProperty) \ + V(SetProperty) \ + V(InvokeBuiltin) \ + V(RegExpCEntry) +#else +#define CODE_STUB_LIST_ARM(V) +#endif + +// Combined list of code stubs. +#define CODE_STUB_LIST(V) \ + CODE_STUB_LIST_ALL(V) \ + CODE_STUB_LIST_ARM(V) // Stub is base classes of all stubs. class CodeStub BASE_EMBEDDED { public: enum Major { - CallFunction, - GenericBinaryOp, - SmiOp, - Compare, - RecordWrite, // Last stub that allows stub calls inside. - ConvertToDouble, - WriteInt32ToHeapNumber, - StackCheck, - UnarySub, - RevertToNumber, - ToBoolean, - Instanceof, - CounterOp, - ArgumentsAccess, - Runtime, - CEntry, - JSEntry, - GetProperty, // ARM only - SetProperty, // ARM only - InvokeBuiltin, // ARM only - RegExpCEntry, // ARM only +#define DEF_ENUM(name) name, + CODE_STUB_LIST(DEF_ENUM) +#undef DEF_ENUM + NoCache, // marker for stubs that do custom caching NUMBER_OF_IDS }; @@ -73,6 +92,12 @@ class CodeStub BASE_EMBEDDED { virtual ~CodeStub() {} + // Override these methods to provide a custom caching mechanism for + // an individual type of code stub. + virtual bool GetCustomCache(Code** code_out) { return false; } + virtual void SetCustomCache(Code* value) { } + virtual bool has_custom_cache() { return false; } + protected: static const int kMajorBits = 5; static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits; diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc index 096a1a1910..f2788a8838 100644 --- a/deps/v8/src/codegen.cc +++ b/deps/v8/src/codegen.cc @@ -274,7 +274,7 @@ void CodeGenerator::SetFunctionInfo(Handle fun, } -static Handle ComputeLazyCompile(int argc) { +Handle CodeGenerator::ComputeLazyCompile(int argc) { CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code); } @@ -551,4 +551,20 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) { } +bool ApiGetterEntryStub::GetCustomCache(Code** code_out) { + Object* cache = info()->load_stub_cache(); + if (cache->IsUndefined()) { + return false; + } else { + *code_out = Code::cast(cache); + return true; + } +} + + +void ApiGetterEntryStub::SetCustomCache(Code* value) { + info()->set_load_stub_cache(value); +} + + } } // namespace v8::internal diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index 1209f36ec6..fc4a53b2e7 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -56,6 +56,7 @@ // ~CodeGenerator // ProcessDeferred // GenCode +// ComputeLazyCompile // BuildBoilerplate // ComputeCallInitialize // ComputeCallInitializeInLoop @@ -300,7 +301,7 @@ class CEntryStub : public CodeStub { Label* throw_normal_exception, Label* throw_termination_exception, Label* throw_out_of_memory_exception, - StackFrame::Type frame_type, + ExitFrame::Mode mode, bool do_gc, bool always_allocate_scope); void GenerateThrowTOS(MacroAssembler* masm); @@ -319,6 +320,32 @@ class CEntryStub : public CodeStub { }; +class ApiGetterEntryStub : public CodeStub { + public: + ApiGetterEntryStub(Handle info, + ApiFunction* fun) + : info_(info), + fun_(fun) { } + void Generate(MacroAssembler* masm); + virtual bool has_custom_cache() { return true; } + virtual bool GetCustomCache(Code** code_out); + virtual void SetCustomCache(Code* value); + + static const int kStackSpace = 6; + static const int kArgc = 4; + private: + Handle info() { return info_; } + ApiFunction* fun() { return fun_; } + Major MajorKey() { return NoCache; } + int MinorKey() { return 0; } + const char* GetName() { return "ApiEntryStub"; } + // The accessor info associated with the function. + Handle info_; + // The function to be called. + ApiFunction* fun_; +}; + + class CEntryDebugBreakStub : public CEntryStub { public: CEntryDebugBreakStub() : CEntryStub(1) { } diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 2e55683b2b..bad209e138 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -46,13 +46,25 @@ class CodeGenSelector: public AstVisitor { public: enum CodeGenTag { NORMAL, FAST }; - CodeGenSelector() : has_supported_syntax_(true) {} + CodeGenSelector() + : has_supported_syntax_(true), + location_(Location::Nowhere()) { + } CodeGenTag Select(FunctionLiteral* fun); private: + void VisitDeclarations(ZoneList* decls); void VisitStatements(ZoneList* stmts); + // Visit an expression in effect context with a desired location of + // nowhere. + void VisitAsEffect(Expression* expr); + + // Visit an expression in value context with a desired location of + // temporary. + void VisitAsValue(Expression* expr); + // AST node visit functions. #define DECLARE_VISIT(type) virtual void Visit##type(type* node); AST_NODE_LIST(DECLARE_VISIT) @@ -60,6 +72,9 @@ class CodeGenSelector: public AstVisitor { bool has_supported_syntax_; + // The desired location of the currently visited expression. + Location location_; + DISALLOW_COPY_AND_ASSIGN(CodeGenSelector); }; @@ -107,7 +122,7 @@ static Handle MakeCode(FunctionLiteral* literal, CodeGenSelector selector; CodeGenSelector::CodeGenTag code_gen = selector.Select(literal); if (code_gen == CodeGenSelector::FAST) { - return FastCodeGenerator::MakeCode(literal, script); + return FastCodeGenerator::MakeCode(literal, script, is_eval); } ASSERT(code_gen == CodeGenSelector::NORMAL); } @@ -450,15 +465,17 @@ bool Compiler::CompileLazy(Handle shared, CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) { Scope* scope = fun->scope(); - if (!scope->is_global_scope()) return NORMAL; + if (!scope->is_global_scope()) { + if (FLAG_trace_bailout) PrintF("Non-global scope\n"); + return NORMAL; + } ASSERT(scope->num_heap_slots() == 0); ASSERT(scope->arguments() == NULL); - if (!scope->declarations()->is_empty()) return NORMAL; - if (fun->materialized_literal_count() > 0) return NORMAL; - if (fun->body()->is_empty()) return NORMAL; - has_supported_syntax_ = true; + VisitDeclarations(fun->scope()->declarations()); + if (!has_supported_syntax_) return NORMAL; + VisitStatements(fun->body()); return has_supported_syntax_ ? FAST : NORMAL; } @@ -480,34 +497,66 @@ CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) { } while (false) +void CodeGenSelector::VisitDeclarations(ZoneList* decls) { + for (int i = 0; i < decls->length(); i++) { + Visit(decls->at(i)); + CHECK_BAILOUT; + } +} + + void CodeGenSelector::VisitStatements(ZoneList* stmts) { for (int i = 0, len = stmts->length(); i < len; i++) { - CHECK_BAILOUT; Visit(stmts->at(i)); + CHECK_BAILOUT; + } +} + + +void CodeGenSelector::VisitAsEffect(Expression* expr) { + if (location_.is_nowhere()) { + Visit(expr); + } else { + Location saved = location_; + location_ = Location::Nowhere(); + Visit(expr); + location_ = saved; + } +} + + +void CodeGenSelector::VisitAsValue(Expression* expr) { + if (location_.is_temporary()) { + Visit(expr); + } else { + Location saved = location_; + location_ = Location::Temporary(); + Visit(expr); + location_ = saved; } } void CodeGenSelector::VisitDeclaration(Declaration* decl) { - BAILOUT("Declaration"); + Variable* var = decl->proxy()->var(); + if (!var->is_global() || var->mode() == Variable::CONST) { + BAILOUT("Non-global declaration"); + } } void CodeGenSelector::VisitBlock(Block* stmt) { - BAILOUT("Block"); + VisitStatements(stmt->statements()); } void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) { - Expression* expr = stmt->expression(); - Visit(expr); - CHECK_BAILOUT; - expr->set_location(Location::Nowhere()); + VisitAsEffect(stmt->expression()); } void CodeGenSelector::VisitEmptyStatement(EmptyStatement* stmt) { - BAILOUT("EmptyStatement"); + // EmptyStatement is supported. } @@ -527,7 +576,7 @@ void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) { void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) { - Visit(stmt->expression()); + VisitAsValue(stmt->expression()); } @@ -582,7 +631,10 @@ void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) { void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) { - BAILOUT("FunctionLiteral"); + if (!expr->AllowsLazyCompilation()) { + BAILOUT("FunctionLiteral does not allow lazy compilation"); + } + expr->set_location(location_); } @@ -598,37 +650,88 @@ void CodeGenSelector::VisitConditional(Conditional* expr) { void CodeGenSelector::VisitSlot(Slot* expr) { - Slot::Type type = expr->type(); - if (type != Slot::PARAMETER && type != Slot::LOCAL) { - BAILOUT("non-parameter/non-local slot reference"); - } + UNREACHABLE(); } void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) { Expression* rewrite = expr->var()->rewrite(); - if (rewrite == NULL) BAILOUT("global variable reference"); - Visit(rewrite); + // A rewrite of NULL indicates a global variable. + if (rewrite != NULL) { + // Non-global. + Slot* slot = rewrite->AsSlot(); + if (slot == NULL) { + // This is a variable rewritten to an explicit property access + // on the arguments object. + BAILOUT("non-global/non-slot variable reference"); + } + + Slot::Type type = slot->type(); + if (type != Slot::PARAMETER && type != Slot::LOCAL) { + BAILOUT("non-parameter/non-local slot reference"); + } + } + expr->set_location(location_); } void CodeGenSelector::VisitLiteral(Literal* expr) { - // All literals are supported. + expr->set_location(location_); } void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) { - BAILOUT("RegExpLiteral"); + expr->set_location(location_); } void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) { - BAILOUT("ObjectLiteral"); + ZoneList* properties = expr->properties(); + + for (int i = 0, len = properties->length(); i < len; i++) { + ObjectLiteral::Property* property = properties->at(i); + if (property->IsCompileTimeValue()) continue; + + switch (property->kind()) { + case ObjectLiteral::Property::CONSTANT: + UNREACHABLE(); + + // For (non-compile-time) materialized literals and computed + // properties with symbolic keys we will use an IC and therefore not + // generate code for the key. + case ObjectLiteral::Property::COMPUTED: // Fall through. + case ObjectLiteral::Property::MATERIALIZED_LITERAL: + if (property->key()->handle()->IsSymbol()) { + break; + } + // Fall through. + + // In all other cases we need the key's value on the stack + // for a runtime call. (Relies on TEMP meaning STACK.) + case ObjectLiteral::Property::GETTER: // Fall through. + case ObjectLiteral::Property::SETTER: // Fall through. + case ObjectLiteral::Property::PROTOTYPE: + VisitAsValue(property->key()); + CHECK_BAILOUT; + break; + } + VisitAsValue(property->value()); + CHECK_BAILOUT; + } + expr->set_location(location_); } void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) { - BAILOUT("ArrayLiteral"); + ZoneList* subexprs = expr->values(); + for (int i = 0, len = subexprs->length(); i < len; i++) { + Expression* subexpr = subexprs->at(i); + if (subexpr->AsLiteral() != NULL) continue; + if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; + VisitAsValue(subexpr); + CHECK_BAILOUT; + } + expr->set_location(location_); } @@ -640,7 +743,10 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) { void CodeGenSelector::VisitAssignment(Assignment* expr) { // We support plain non-compound assignments to parameters and // non-context (stack-allocated) locals. - if (expr->starts_initialization_block()) BAILOUT("initialization block"); + if (expr->starts_initialization_block() || + expr->ends_initialization_block()) { + BAILOUT("initialization block start"); + } Token::Value op = expr->op(); if (op == Token::INIT_CONST) BAILOUT("initialize constant"); @@ -649,15 +755,18 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) { } Variable* var = expr->target()->AsVariableProxy()->AsVariable(); - if (var == NULL || var->is_global()) BAILOUT("non-variable assignment"); + if (var == NULL) BAILOUT("non-variable assignment"); - ASSERT(var->slot() != NULL); - Slot::Type type = var->slot()->type(); - if (type != Slot::PARAMETER && type != Slot::LOCAL) { - BAILOUT("non-parameter/non-local slot assignment"); + if (!var->is_global()) { + ASSERT(var->slot() != NULL); + Slot::Type type = var->slot()->type(); + if (type != Slot::PARAMETER && type != Slot::LOCAL) { + BAILOUT("non-parameter/non-local slot assignment"); + } } - Visit(expr->value()); + VisitAsValue(expr->value()); + expr->set_location(location_); } @@ -667,22 +776,64 @@ void CodeGenSelector::VisitThrow(Throw* expr) { void CodeGenSelector::VisitProperty(Property* expr) { - BAILOUT("Property"); + VisitAsValue(expr->obj()); + CHECK_BAILOUT; + VisitAsValue(expr->key()); + expr->set_location(location_); } void CodeGenSelector::VisitCall(Call* expr) { - BAILOUT("Call"); + Expression* fun = expr->expression(); + ZoneList* args = expr->arguments(); + Variable* var = fun->AsVariableProxy()->AsVariable(); + + // Check for supported calls + if (var != NULL && var->is_possibly_eval()) { + BAILOUT("Call to a function named 'eval'"); + } else if (var != NULL && !var->is_this() && var->is_global()) { + // ---------------------------------- + // JavaScript example: 'foo(1, 2, 3)' // foo is global + // ---------------------------------- + } else { + BAILOUT("Call to a non-global function"); + } + // Check all arguments to the call. (Relies on TEMP meaning STACK.) + for (int i = 0; i < args->length(); i++) { + VisitAsValue(args->at(i)); + CHECK_BAILOUT; + } + expr->set_location(location_); } void CodeGenSelector::VisitCallNew(CallNew* expr) { - BAILOUT("CallNew"); + VisitAsValue(expr->expression()); + CHECK_BAILOUT; + ZoneList* args = expr->arguments(); + // Check all arguments to the call + for (int i = 0; i < args->length(); i++) { + VisitAsValue(args->at(i)); + CHECK_BAILOUT; + } + expr->set_location(location_); } void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) { - BAILOUT("CallRuntime"); + // In case of JS runtime function bail out. + if (expr->function() == NULL) BAILOUT("call JS runtime function"); + // Check for inline runtime call + if (expr->name()->Get(0) == '_' && + CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) { + BAILOUT("inlined runtime call"); + } + // Check all arguments to the call. (Relies on TEMP meaning STACK.) + for (int i = 0; i < expr->arguments()->length(); i++) { + VisitAsValue(expr->arguments()->at(i)); + CHECK_BAILOUT; + } + expr->set_location(location_); } @@ -697,7 +848,19 @@ void CodeGenSelector::VisitCountOperation(CountOperation* expr) { void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) { - BAILOUT("BinaryOperation"); + switch (expr->op()) { + case Token::OR: + VisitAsValue(expr->left()); + CHECK_BAILOUT; + // The location for the right subexpression is the same as for the + // whole expression so we call Visit directly. + Visit(expr->right()); + break; + + default: + BAILOUT("Unsupported binary operation"); + } + expr->set_location(location_); } diff --git a/deps/v8/src/conversions-inl.h b/deps/v8/src/conversions-inl.h index 8c875d75bf..ba7220a4a6 100644 --- a/deps/v8/src/conversions-inl.h +++ b/deps/v8/src/conversions-inl.h @@ -84,7 +84,7 @@ int32_t DoubleToInt32(double x) { static const double two32 = 4294967296.0; static const double two31 = 2147483648.0; if (!isfinite(x) || x == 0) return 0; - if (x < 0 || x >= two32) x = fmod(x, two32); + if (x < 0 || x >= two32) x = modulo(x, two32); x = (x >= 0) ? floor(x) : ceil(x) + two32; return (int32_t) ((x >= two31) ? x - two32 : x); } diff --git a/deps/v8/src/conversions.cc b/deps/v8/src/conversions.cc index 2a3db7bb69..3e66d286c2 100644 --- a/deps/v8/src/conversions.cc +++ b/deps/v8/src/conversions.cc @@ -664,7 +664,7 @@ char* DoubleToRadixCString(double value, int radix) { int integer_pos = kBufferSize - 2; do { integer_buffer[integer_pos--] = - chars[static_cast(fmod(integer_part, radix))]; + chars[static_cast(modulo(integer_part, radix))]; integer_part /= radix; } while (integer_part >= 1.0); // Sanity check. diff --git a/deps/v8/src/conversions.h b/deps/v8/src/conversions.h index b6589cb5ca..67f7d53f51 100644 --- a/deps/v8/src/conversions.h +++ b/deps/v8/src/conversions.h @@ -31,6 +31,7 @@ namespace v8 { namespace internal { + // The fast double-to-int conversion routine does not guarantee // rounding towards zero. // The result is unspecified if x is infinite or NaN, or if the rounded diff --git a/deps/v8/src/debug-delay.js b/deps/v8/src/debug-delay.js index d9447bd27e..35f7fcd7e4 100644 --- a/deps/v8/src/debug-delay.js +++ b/deps/v8/src/debug-delay.js @@ -1243,6 +1243,8 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) this.threadsRequest_(request, response); } else if (request.command == 'suspend') { this.suspendRequest_(request, response); + } else if (request.command == 'version') { + this.versionRequest_(request, response); } else { throw new Error('Unknown command "' + request.command + '" in request'); } @@ -1911,11 +1913,17 @@ DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) { DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) { - // TODO(peter.rybin): probably we need some body field here. response.running = false; }; +DebugCommandProcessor.prototype.versionRequest_ = function(request, response) { + response.body = { + V8Version: %GetV8Version() + } +}; + + // Check whether the previously processed command caused the VM to become // running. DebugCommandProcessor.prototype.isRunning = function() { diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index 5251e344b5..32b69db394 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -222,6 +222,18 @@ Handle Factory::NewPixelArray(int length, } +Handle Factory::NewExternalArray(int length, + ExternalArrayType array_type, + void* external_pointer, + PretenureFlag pretenure) { + ASSERT(0 <= length); + CALL_HEAP_FUNCTION(Heap::AllocateExternalArray(length, + array_type, + external_pointer, + pretenure), ExternalArray); +} + + Handle Factory::NewMap(InstanceType type, int instance_size) { CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map); } diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 7223f081e5..cb438e95e7 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -155,10 +155,17 @@ class Factory : public AllStatic { static Handle NewByteArray(int length, PretenureFlag pretenure = NOT_TENURED); - static Handle NewPixelArray(int length, + static Handle NewPixelArray( + int length, uint8_t* external_pointer, PretenureFlag pretenure = NOT_TENURED); + static Handle NewExternalArray( + int length, + ExternalArrayType array_type, + void* external_pointer, + PretenureFlag pretenure = NOT_TENURED); + static Handle NewMap(InstanceType type, int instance_size); static Handle NewFunctionPrototype(Handle function); diff --git a/deps/v8/src/fast-codegen.cc b/deps/v8/src/fast-codegen.cc index 4ec6a524f2..8655e97a86 100644 --- a/deps/v8/src/fast-codegen.cc +++ b/deps/v8/src/fast-codegen.cc @@ -29,16 +29,19 @@ #include "codegen-inl.h" #include "fast-codegen.h" +#include "stub-cache.h" +#include "debug.h" namespace v8 { namespace internal { Handle FastCodeGenerator::MakeCode(FunctionLiteral* fun, - Handle