diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore index 685e9a2f9d..e5687e730e 100644 --- a/deps/v8/.gitignore +++ b/deps/v8/.gitignore @@ -10,6 +10,10 @@ *.suo *.user *.xcodeproj +*.idb +*.pdb +#*# +*~ d8 d8_g shell diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index d07c4586d5..d13d74f545 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,24 @@ +2009-10-16: Version 1.3.16 + + X64: Convert smis to holding 32 bits of payload. + + Introduce v8::Integer::NewFromUnsigned method. + + Add missing null check in Context::GetCurrent. + + Add trim, trimLeft and trimRight methods to String + Patch by Jan de Mooij + + Implement ES5 Array.isArray + Patch by Jan de Mooij + + Skip access checks for hidden properties. + + Add String::Concat(Handle left, Handle right) to the V8 API. + + Fix GYP-based builds of V8. + + 2009-10-07: Version 1.3.15 Expand the maximum size of the code space to 512MB for 64-bit mode. diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct old mode 100644 new mode 100755 index e1a37f34f5..af8119bfdb --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -372,7 +372,8 @@ CCTEST_EXTRA_FLAGS = { 'CPPDEFINES': ['V8_TARGET_ARCH_IA32'] }, 'arch:x64': { - 'CPPDEFINES': ['V8_TARGET_ARCH_X64'] + 'CPPDEFINES': ['V8_TARGET_ARCH_X64'], + 'LINKFLAGS': ['/STACK:2091752'] }, } } @@ -473,7 +474,7 @@ SAMPLE_FLAGS = { }, 'arch:x64': { 'CPPDEFINES': ['V8_TARGET_ARCH_X64'], - 'LINKFLAGS': ['/MACHINE:X64'] + 'LINKFLAGS': ['/MACHINE:X64', '/STACK:2091752'] }, 'mode:debug': { 'CCFLAGS': ['/Od'], diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index adb9f43176..d923f97855 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -756,7 +756,7 @@ class V8EXPORT Value : public Data { /** JS == */ bool Equals(Handle that) const; bool StrictEquals(Handle that) const; - + private: inline bool QuickIsString() const; bool FullIsString() const; @@ -918,6 +918,12 @@ class V8EXPORT String : public Primitive { /** Creates a symbol. Returns one if it exists already.*/ static Local NewSymbol(const char* data, int length = -1); + /** + * Creates a new string by concatenating the left and the right strings + * passed in as parameters. + */ + static Local Concat(Handle left, Handleright); + /** * Creates a new external string using the data defined in the given * resource. The resource is deleted when the external string is no @@ -1036,7 +1042,7 @@ class V8EXPORT String : public Primitive { Value(const Value&); void operator=(const Value&); }; - + private: void VerifyExternalStringResource(ExternalStringResource* val) const; static void CheckCast(v8::Value* obj); @@ -1063,6 +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); int64_t Value() const; static inline Integer* Cast(v8::Value* obj); private: @@ -1193,7 +1200,7 @@ class V8EXPORT Object : public Value { /** Gets a native pointer from an internal field. */ inline void* GetPointerFromInternalField(int index); - + /** Sets a native pointer in an internal field. */ void SetPointerInInternalField(int index, void* value); @@ -1246,7 +1253,7 @@ class V8EXPORT Object : public Value { bool SetHiddenValue(Handle key, Handle value); Local GetHiddenValue(Handle key); bool DeleteHiddenValue(Handle key); - + /** * Returns true if this is an instance of an api function (one * created from a function created from a function template) and has @@ -1277,10 +1284,11 @@ class V8EXPORT Object : public Value { Object(); static void CheckCast(Value* obj); Local CheckedGetInternalField(int index); + void* SlowGetPointerFromInternalField(int index); /** * If quick access to the internal field is possible this method - * returns the value. Otherwise an empty handle is returned. + * returns the value. Otherwise an empty handle is returned. */ inline Local UncheckedGetInternalField(int index); }; @@ -2719,12 +2727,37 @@ const int kHeapObjectTag = 1; const int kHeapObjectTagSize = 2; const intptr_t kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1; - // Tag information for Smi. const int kSmiTag = 0; const int kSmiTagSize = 1; const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1; +template struct SmiConstants; + +// Smi constants for 32-bit systems. +template <> struct SmiConstants<4> { + static const int kSmiShiftSize = 0; + static const int kSmiValueSize = 31; + static inline int SmiToInt(internal::Object* value) { + int shift_bits = kSmiTagSize + kSmiShiftSize; + // Throw away top 32 bits and shift down (requires >> to be sign extending). + return static_cast(reinterpret_cast(value)) >> shift_bits; + } +}; + +// Smi constants for 64-bit systems. +template <> struct SmiConstants<8> { + static const int kSmiShiftSize = 31; + static const int kSmiValueSize = 32; + static inline int SmiToInt(internal::Object* value) { + int shift_bits = kSmiTagSize + kSmiShiftSize; + // Shift down and throw away top 32 bits. + return static_cast(reinterpret_cast(value) >> shift_bits); + } +}; + +const int kSmiShiftSize = SmiConstants::kSmiShiftSize; +const int kSmiValueSize = SmiConstants::kSmiValueSize; /** * This class exports constants and functionality from within v8 that @@ -2743,7 +2776,6 @@ class Internals { static const int kJSObjectHeaderSize = 3 * sizeof(void*); static const int kFullStringRepresentationMask = 0x07; static const int kExternalTwoByteRepresentationTag = 0x03; - static const int kAlignedPointerShift = 2; // These constants are compiler dependent so their values must be // defined within the implementation. @@ -2761,7 +2793,23 @@ class Internals { } static inline int SmiValue(internal::Object* value) { - return static_cast(reinterpret_cast(value)) >> kSmiTagSize; + return SmiConstants::SmiToInt(value); + } + + static inline int GetInstanceType(internal::Object* obj) { + typedef internal::Object O; + O* map = ReadField(obj, kHeapObjectMapOffset); + return ReadField(map, kMapInstanceTypeOffset); + } + + static inline void* GetExternalPointer(internal::Object* obj) { + if (HasSmiTag(obj)) { + return obj; + } else if (GetInstanceType(obj) == kProxyType) { + return ReadField(obj, kProxyProxyOffset); + } else { + return NULL; + } } static inline bool IsExternalTwoByteString(int instance_type) { @@ -2921,9 +2969,7 @@ Local Object::UncheckedGetInternalField(int index) { typedef internal::Object O; typedef internal::Internals I; O* obj = *reinterpret_cast(this); - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); - if (instance_type == I::kJSObjectType) { + if (I::GetInstanceType(obj) == I::kJSObjectType) { // If the object is a plain JSObject, which is the common case, // we know where to find the internal fields and can return the // value directly. @@ -2948,25 +2994,27 @@ void* External::Unwrap(Handle obj) { void* External::QuickUnwrap(Handle wrapper) { typedef internal::Object O; - typedef internal::Internals I; O* obj = *reinterpret_cast(const_cast(*wrapper)); - if (I::HasSmiTag(obj)) { - int value = I::SmiValue(obj) << I::kAlignedPointerShift; - return reinterpret_cast(value); - } else { - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); - if (instance_type == I::kProxyType) { - return I::ReadField(obj, I::kProxyProxyOffset); - } else { - return NULL; - } - } + return internal::Internals::GetExternalPointer(obj); } void* Object::GetPointerFromInternalField(int index) { - return External::Unwrap(GetInternalField(index)); + typedef internal::Object O; + typedef internal::Internals I; + + O* obj = *reinterpret_cast(this); + + if (I::GetInstanceType(obj) == I::kJSObjectType) { + // If the object is a plain JSObject, which is the common case, + // we know where to find the internal fields and can return the + // value directly. + int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index); + O* value = I::ReadField(obj, offset); + return I::GetExternalPointer(value); + } + + return SlowGetPointerFromInternalField(index); } @@ -2982,10 +3030,8 @@ String::ExternalStringResource* String::GetExternalStringResource() const { typedef internal::Object O; typedef internal::Internals I; O* obj = *reinterpret_cast(const_cast(this)); - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); String::ExternalStringResource* result; - if (I::IsExternalTwoByteString(instance_type)) { + if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) { void* value = I::ReadField(obj, I::kStringResourceOffset); result = reinterpret_cast(value); } else { @@ -3011,9 +3057,7 @@ bool Value::QuickIsString() const { typedef internal::Internals I; O* obj = *reinterpret_cast(const_cast(this)); if (!I::HasHeapObjectTag(obj)) return false; - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); - return (instance_type < I::kFirstNonstringType); + return (I::GetInstanceType(obj) < I::kFirstNonstringType); } @@ -3025,6 +3069,15 @@ 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/SConscript b/deps/v8/src/SConscript index b6c2b4d266..85fd724964 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -34,51 +34,129 @@ Import('context') SOURCES = { - 'all': [ - 'accessors.cc', 'allocation.cc', 'api.cc', 'assembler.cc', 'ast.cc', - 'bootstrapper.cc', 'builtins.cc', 'checks.cc', 'code-stubs.cc', - 'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc', - 'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc', - 'debug-agent.cc', 'disassembler.cc', 'execution.cc', 'factory.cc', - 'flags.cc', 'frame-element.cc', 'frames.cc', 'func-name-inferrer.cc', - 'global-handles.cc', 'handles.cc', 'hashmap.cc', 'heap.cc', - 'heap-profiler.cc', 'ic.cc', 'interpreter-irregexp.cc', 'jsregexp.cc', - 'jump-target.cc', 'log.cc', 'log-utils.cc', 'mark-compact.cc', - 'messages.cc', 'objects.cc', 'oprofile-agent.cc', 'parser.cc', - 'property.cc', 'regexp-macro-assembler.cc', - 'regexp-macro-assembler-irregexp.cc', 'regexp-stack.cc', - 'register-allocator.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc', - 'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc', - 'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc', - 'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc', - 'v8.cc', 'v8threads.cc', 'variables.cc', 'version.cc', - 'virtual-frame.cc', 'zone.cc' - ], - 'arch:arm': [ - 'arm/assembler-arm.cc', 'arm/builtins-arm.cc', 'arm/codegen-arm.cc', - 'arm/constants-arm.cc', 'arm/cpu-arm.cc', 'arm/disasm-arm.cc', - 'arm/debug-arm.cc', 'arm/frames-arm.cc', 'arm/ic-arm.cc', - 'arm/jump-target-arm.cc', 'arm/macro-assembler-arm.cc', - 'arm/regexp-macro-assembler-arm.cc', 'arm/register-allocator-arm.cc', - 'arm/stub-cache-arm.cc', 'arm/virtual-frame-arm.cc' - ], - 'arch:ia32': [ - 'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc', - 'ia32/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc', - 'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-ia32.cc', - 'ia32/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc', - 'ia32/regexp-macro-assembler-ia32.cc', - 'ia32/register-allocator-ia32.cc', 'ia32/stub-cache-ia32.cc', - 'ia32/virtual-frame-ia32.cc' - ], - 'arch:x64': [ - 'x64/assembler-x64.cc', 'x64/builtins-x64.cc', 'x64/codegen-x64.cc', - 'x64/cpu-x64.cc', 'x64/disasm-x64.cc', 'x64/debug-x64.cc', - 'x64/frames-x64.cc', 'x64/ic-x64.cc', 'x64/jump-target-x64.cc', - 'x64/macro-assembler-x64.cc', 'x64/regexp-macro-assembler-x64.cc', - 'x64/register-allocator-x64.cc', 'x64/stub-cache-x64.cc', - 'x64/virtual-frame-x64.cc' - ], + 'all': Split(""" + accessors.cc + allocation.cc + api.cc + assembler.cc + ast.cc + bootstrapper.cc + builtins.cc + checks.cc + code-stubs.cc + codegen.cc + compilation-cache.cc + compiler.cc + contexts.cc + conversions.cc + counters.cc + dateparser.cc + debug-agent.cc + debug.cc + disassembler.cc + execution.cc + factory.cc + fast-codegen.cc + flags.cc + frame-element.cc + frames.cc + func-name-inferrer.cc + global-handles.cc + handles.cc + hashmap.cc + heap-profiler.cc + heap.cc + ic.cc + interpreter-irregexp.cc + jsregexp.cc + jump-target.cc + log-utils.cc + log.cc + mark-compact.cc + messages.cc + objects.cc + oprofile-agent.cc + parser.cc + property.cc + regexp-macro-assembler-irregexp.cc + regexp-macro-assembler.cc + regexp-stack.cc + register-allocator.cc + rewriter.cc + runtime.cc + scanner.cc + scopeinfo.cc + scopes.cc + serialize.cc + snapshot-common.cc + spaces.cc + string-stream.cc + stub-cache.cc + token.cc + top.cc + unicode.cc + usage-analyzer.cc + utils.cc + v8-counters.cc + v8.cc + v8threads.cc + variables.cc + version.cc + virtual-frame.cc + zone.cc + """), + 'arch:arm': Split(""" + arm/assembler-arm.cc + arm/builtins-arm.cc + arm/codegen-arm.cc + arm/constants-arm.cc + arm/cpu-arm.cc + arm/debug-arm.cc + arm/disasm-arm.cc + arm/fast-codegen-arm.cc + arm/frames-arm.cc + arm/ic-arm.cc + arm/jump-target-arm.cc + arm/macro-assembler-arm.cc + arm/regexp-macro-assembler-arm.cc + arm/register-allocator-arm.cc + arm/stub-cache-arm.cc + arm/virtual-frame-arm.cc + """), + 'arch:ia32': Split(""" + ia32/assembler-ia32.cc + ia32/builtins-ia32.cc + ia32/codegen-ia32.cc + ia32/cpu-ia32.cc + ia32/debug-ia32.cc + ia32/disasm-ia32.cc + ia32/fast-codegen-ia32.cc + ia32/frames-ia32.cc + ia32/ic-ia32.cc + ia32/jump-target-ia32.cc + ia32/macro-assembler-ia32.cc + ia32/regexp-macro-assembler-ia32.cc + ia32/register-allocator-ia32.cc + ia32/stub-cache-ia32.cc + ia32/virtual-frame-ia32.cc + """), + 'arch:x64': Split(""" + x64/assembler-x64.cc + x64/builtins-x64.cc + x64/codegen-x64.cc + x64/cpu-x64.cc + x64/debug-x64.cc + x64/disasm-x64.cc + x64/fast-codegen-x64.cc + x64/frames-x64.cc + x64/ic-x64.cc + x64/jump-target-x64.cc + x64/macro-assembler-x64.cc + x64/regexp-macro-assembler-x64.cc + x64/register-allocator-x64.cc + x64/stub-cache-x64.cc + x64/virtual-frame-x64.cc + """), 'simulator:arm': ['arm/simulator-arm.cc'], 'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'], 'os:linux': ['platform-linux.cc', 'platform-posix.cc'], diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 25354b269c..ffbe98eaf6 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -2290,7 +2290,7 @@ void v8::Object::SetIndexedPropertiesToPixelData(uint8_t* data, int length) { ON_BAILOUT("v8::SetElementsToPixelData()", return); ENTER_V8; HandleScope scope; - if (!ApiCheck(i::Smi::IsValid(length), + if (!ApiCheck(length <= i::PixelArray::kMaxLength, "v8::Object::SetIndexedPropertiesToPixelData()", "length exceeds max acceptable value")) { return; @@ -2578,7 +2578,16 @@ void v8::Object::SetInternalField(int index, v8::Handle value) { void v8::Object::SetPointerInInternalField(int index, void* value) { - SetInternalField(index, External::Wrap(value)); + i::Object* as_object = reinterpret_cast(value); + if (as_object->IsSmi()) { + Utils::OpenHandle(this)->SetInternalField(index, as_object); + return; + } + HandleScope scope; + i::Handle proxy = + i::Factory::NewProxy(reinterpret_cast(value), i::TENURED); + if (!proxy.is_null()) + Utils::OpenHandle(this)->SetInternalField(index, *proxy); } @@ -2760,7 +2769,9 @@ v8::Local Context::GetEntered() { v8::Local Context::GetCurrent() { if (IsDeadCheck("v8::Context::GetCurrent()")) return Local(); - i::Handle context(i::Top::global_context()); + i::Handle current = i::Top::global_context(); + if (current.is_null()) return Local(); + i::Handle context = i::Handle::cast(current); return Utils::ToLocal(context); } @@ -2837,36 +2848,39 @@ static void* ExternalValueImpl(i::Handle obj) { } -static const intptr_t kAlignedPointerMask = 3; - Local v8::External::Wrap(void* data) { STATIC_ASSERT(sizeof(data) == sizeof(i::Address)); LOG_API("External::Wrap"); EnsureInitialized("v8::External::Wrap()"); ENTER_V8; - if ((reinterpret_cast(data) & kAlignedPointerMask) == 0) { - uintptr_t data_ptr = reinterpret_cast(data); - intptr_t data_value = - static_cast(data_ptr >> i::Internals::kAlignedPointerShift); - STATIC_ASSERT(sizeof(data_ptr) == sizeof(data_value)); - if (i::Smi::IsIntptrValid(data_value)) { - i::Handle obj(i::Smi::FromIntptr(data_value)); - return Utils::ToLocal(obj); - } + i::Object* as_object = reinterpret_cast(data); + if (as_object->IsSmi()) { + return Utils::ToLocal(i::Handle(as_object)); } return ExternalNewImpl(data); } +void* v8::Object::SlowGetPointerFromInternalField(int index) { + i::Handle obj = Utils::OpenHandle(this); + i::Object* value = obj->GetInternalField(index); + if (value->IsSmi()) { + return value; + } else if (value->IsProxy()) { + return reinterpret_cast(i::Proxy::cast(value)->proxy()); + } else { + return NULL; + } +} + + void* v8::External::FullUnwrap(v8::Handle wrapper) { if (IsDeadCheck("v8::External::Unwrap()")) return 0; i::Handle obj = Utils::OpenHandle(*wrapper); void* result; if (obj->IsSmi()) { // The external value was an aligned pointer. - uintptr_t value = static_cast( - i::Smi::cast(*obj)->value()) << i::Internals::kAlignedPointerShift; - result = reinterpret_cast(value); + result = *obj; } else if (obj->IsProxy()) { result = ExternalValueImpl(obj); } else { @@ -2912,6 +2926,18 @@ Local v8::String::New(const char* data, int length) { } +Local v8::String::Concat(Handle left, Handle right) { + EnsureInitialized("v8::String::New()"); + LOG_API("String::New(char)"); + ENTER_V8; + i::Handle left_string = Utils::OpenHandle(*left); + i::Handle right_string = Utils::OpenHandle(*right); + i::Handle result = i::Factory::NewConsString(left_string, + right_string); + return Utils::ToLocal(result); +} + + Local v8::String::NewUndetectable(const char* data, int length) { EnsureInitialized("v8::String::NewUndetectable()"); LOG_API("String::NewUndetectable(char)"); diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index 5417ed7d36..48cc09081d 100644 --- a/deps/v8/src/arm/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -110,7 +110,7 @@ Address* RelocInfo::target_reference_address() { Address RelocInfo::call_address() { - ASSERT(IsCallInstruction()); + ASSERT(IsPatchedReturnSequence()); // The 2 instructions offset assumes patched return sequence. ASSERT(IsJSReturn(rmode())); return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize); @@ -118,7 +118,7 @@ Address RelocInfo::call_address() { void RelocInfo::set_call_address(Address target) { - ASSERT(IsCallInstruction()); + ASSERT(IsPatchedReturnSequence()); // The 2 instructions offset assumes patched return sequence. ASSERT(IsJSReturn(rmode())); Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target; @@ -131,7 +131,7 @@ Object* RelocInfo::call_object() { Object** RelocInfo::call_object_address() { - ASSERT(IsCallInstruction()); + ASSERT(IsPatchedReturnSequence()); // The 2 instructions offset assumes patched return sequence. ASSERT(IsJSReturn(rmode())); return reinterpret_cast(pc_ + 2 * Assembler::kInstrSize); @@ -143,7 +143,7 @@ void RelocInfo::set_call_object(Object* target) { } -bool RelocInfo::IsCallInstruction() { +bool RelocInfo::IsPatchedReturnSequence() { // On ARM a "call instruction" is actually two instructions. // mov lr, pc // ldr pc, [pc, #XXX] diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index cdd32f30f8..147c5e354c 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -1539,191 +1539,200 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { } -void CodeGenerator::VisitLoopStatement(LoopStatement* node) { +void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { #ifdef DEBUG int original_height = frame_->height(); #endif VirtualFrame::SpilledScope spilled_scope; - Comment cmnt(masm_, "[ LoopStatement"); + Comment cmnt(masm_, "[ DoWhileStatement"); CodeForStatementPosition(node); node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); - - // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a - // known result for the test expression, with no side effects. - enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; - if (node->cond() == NULL) { - ASSERT(node->type() == LoopStatement::FOR_LOOP); - info = ALWAYS_TRUE; - } else { - Literal* lit = node->cond()->AsLiteral(); - if (lit != NULL) { - if (lit->IsTrue()) { - info = ALWAYS_TRUE; - } else if (lit->IsFalse()) { - info = ALWAYS_FALSE; - } - } + JumpTarget body(JumpTarget::BIDIRECTIONAL); + + // Label the top of the loop for the backward CFG edge. If the test + // is always true we can use the continue target, and if the test is + // always false there is no need. + ConditionAnalysis info = AnalyzeCondition(node->cond()); + switch (info) { + case ALWAYS_TRUE: + node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); + node->continue_target()->Bind(); + break; + case ALWAYS_FALSE: + node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); + break; + case DONT_KNOW: + node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); + body.Bind(); + break; } - switch (node->type()) { - case LoopStatement::DO_LOOP: { - JumpTarget body(JumpTarget::BIDIRECTIONAL); + CheckStack(); // TODO(1222600): ignore if body contains calls. + VisitAndSpill(node->body()); - // Label the top of the loop for the backward CFG edge. If the test - // is always true we can use the continue target, and if the test is - // always false there is no need. - if (info == ALWAYS_TRUE) { - node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); + // Compile the test. + switch (info) { + case ALWAYS_TRUE: + // If control can fall off the end of the body, jump back to the + // top. + if (has_valid_frame()) { + node->continue_target()->Jump(); + } + break; + case ALWAYS_FALSE: + // If we have a continue in the body, we only have to bind its + // jump target. + if (node->continue_target()->is_linked()) { node->continue_target()->Bind(); - } else if (info == ALWAYS_FALSE) { - node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); - } else { - ASSERT(info == DONT_KNOW); - node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); - body.Bind(); } - - CheckStack(); // TODO(1222600): ignore if body contains calls. - VisitAndSpill(node->body()); - - // Compile the test. - if (info == ALWAYS_TRUE) { - if (has_valid_frame()) { - // If control can fall off the end of the body, jump back to the - // top. - node->continue_target()->Jump(); - } - } else if (info == ALWAYS_FALSE) { - // If we have a continue in the body, we only have to bind its jump - // target. - if (node->continue_target()->is_linked()) { - node->continue_target()->Bind(); - } - } else { - ASSERT(info == DONT_KNOW); - // We have to compile the test expression if it can be reached by - // control flow falling out of the body or via continue. - if (node->continue_target()->is_linked()) { - node->continue_target()->Bind(); - } + break; + case DONT_KNOW: + // We have to compile the test expression if it can be reached by + // control flow falling out of the body or via continue. + if (node->continue_target()->is_linked()) { + node->continue_target()->Bind(); + } + if (has_valid_frame()) { + LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, + &body, node->break_target(), true); if (has_valid_frame()) { - LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, - &body, node->break_target(), true); - if (has_valid_frame()) { - // A invalid frame here indicates that control did not - // fall out of the test expression. - Branch(true, &body); - } + // A invalid frame here indicates that control did not + // fall out of the test expression. + Branch(true, &body); } } break; - } + } - case LoopStatement::WHILE_LOOP: { - // If the test is never true and has no side effects there is no need - // to compile the test or body. - if (info == ALWAYS_FALSE) break; + if (node->break_target()->is_linked()) { + node->break_target()->Bind(); + } + ASSERT(!has_valid_frame() || frame_->height() == original_height); +} - // Label the top of the loop with the continue target for the backward - // CFG edge. - node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); - node->continue_target()->Bind(); - if (info == DONT_KNOW) { - JumpTarget body; - LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, - &body, node->break_target(), true); - if (has_valid_frame()) { - // A NULL frame indicates that control did not fall out of the - // test expression. - Branch(false, node->break_target()); - } - if (has_valid_frame() || body.is_linked()) { - body.Bind(); - } - } +void CodeGenerator::VisitWhileStatement(WhileStatement* node) { +#ifdef DEBUG + int original_height = frame_->height(); +#endif + VirtualFrame::SpilledScope spilled_scope; + Comment cmnt(masm_, "[ WhileStatement"); + CodeForStatementPosition(node); - if (has_valid_frame()) { - CheckStack(); // TODO(1222600): ignore if body contains calls. - VisitAndSpill(node->body()); + // If the test is never true and has no side effects there is no need + // to compile the test or body. + ConditionAnalysis info = AnalyzeCondition(node->cond()); + if (info == ALWAYS_FALSE) return; - // If control flow can fall out of the body, jump back to the top. - if (has_valid_frame()) { - node->continue_target()->Jump(); - } - } - break; + node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); + + // Label the top of the loop with the continue target for the backward + // CFG edge. + node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); + node->continue_target()->Bind(); + + if (info == DONT_KNOW) { + JumpTarget body; + LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, + &body, node->break_target(), true); + if (has_valid_frame()) { + // A NULL frame indicates that control did not fall out of the + // test expression. + Branch(false, node->break_target()); } + if (has_valid_frame() || body.is_linked()) { + body.Bind(); + } + } - case LoopStatement::FOR_LOOP: { - JumpTarget loop(JumpTarget::BIDIRECTIONAL); + if (has_valid_frame()) { + CheckStack(); // TODO(1222600): ignore if body contains calls. + VisitAndSpill(node->body()); - if (node->init() != NULL) { - VisitAndSpill(node->init()); - } + // If control flow can fall out of the body, jump back to the top. + if (has_valid_frame()) { + node->continue_target()->Jump(); + } + } + if (node->break_target()->is_linked()) { + node->break_target()->Bind(); + } + ASSERT(!has_valid_frame() || frame_->height() == original_height); +} - // There is no need to compile the test or body. - if (info == ALWAYS_FALSE) break; - // If there is no update statement, label the top of the loop with the - // continue target, otherwise with the loop target. - if (node->next() == NULL) { - node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); - node->continue_target()->Bind(); - } else { - node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); - loop.Bind(); - } +void CodeGenerator::VisitForStatement(ForStatement* node) { +#ifdef DEBUG + int original_height = frame_->height(); +#endif + VirtualFrame::SpilledScope spilled_scope; + Comment cmnt(masm_, "[ ForStatement"); + CodeForStatementPosition(node); + if (node->init() != NULL) { + VisitAndSpill(node->init()); + } - // If the test is always true, there is no need to compile it. - if (info == DONT_KNOW) { - JumpTarget body; - LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, - &body, node->break_target(), true); - if (has_valid_frame()) { - Branch(false, node->break_target()); - } - if (has_valid_frame() || body.is_linked()) { - body.Bind(); - } - } + // If the test is never true there is no need to compile the test or + // body. + ConditionAnalysis info = AnalyzeCondition(node->cond()); + if (info == ALWAYS_FALSE) return; + + node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); + + // If there is no update statement, label the top of the loop with the + // continue target, otherwise with the loop target. + JumpTarget loop(JumpTarget::BIDIRECTIONAL); + if (node->next() == NULL) { + node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); + node->continue_target()->Bind(); + } else { + node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); + loop.Bind(); + } + // If the test is always true, there is no need to compile it. + if (info == DONT_KNOW) { + JumpTarget body; + LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF, + &body, node->break_target(), true); + if (has_valid_frame()) { + Branch(false, node->break_target()); + } + if (has_valid_frame() || body.is_linked()) { + body.Bind(); + } + } + + if (has_valid_frame()) { + CheckStack(); // TODO(1222600): ignore if body contains calls. + VisitAndSpill(node->body()); + + if (node->next() == NULL) { + // If there is no update statement and control flow can fall out + // of the loop, jump directly to the continue label. if (has_valid_frame()) { - CheckStack(); // TODO(1222600): ignore if body contains calls. - VisitAndSpill(node->body()); - - if (node->next() == NULL) { - // If there is no update statement and control flow can fall out - // of the loop, jump directly to the continue label. - if (has_valid_frame()) { - node->continue_target()->Jump(); - } - } else { - // If there is an update statement and control flow can reach it - // via falling out of the body of the loop or continuing, we - // compile the update statement. - if (node->continue_target()->is_linked()) { - node->continue_target()->Bind(); - } - if (has_valid_frame()) { - // Record source position of the statement as this code which is - // after the code for the body actually belongs to the loop - // statement and not the body. - CodeForStatementPosition(node); - VisitAndSpill(node->next()); - loop.Jump(); - } - } + node->continue_target()->Jump(); + } + } else { + // If there is an update statement and control flow can reach it + // via falling out of the body of the loop or continuing, we + // compile the update statement. + if (node->continue_target()->is_linked()) { + node->continue_target()->Bind(); + } + if (has_valid_frame()) { + // Record source position of the statement as this code which is + // after the code for the body actually belongs to the loop + // statement and not the body. + CodeForStatementPosition(node); + VisitAndSpill(node->next()); + loop.Jump(); } - break; } } - if (node->break_target()->is_linked()) { node->break_target()->Bind(); } - node->continue_target()->Unuse(); - node->break_target()->Unuse(); ASSERT(!has_valid_frame() || frame_->height() == original_height); } @@ -1918,12 +1927,12 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) { } -void CodeGenerator::VisitTryCatch(TryCatch* node) { +void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { #ifdef DEBUG int original_height = frame_->height(); #endif VirtualFrame::SpilledScope spilled_scope; - Comment cmnt(masm_, "[ TryCatch"); + Comment cmnt(masm_, "[ TryCatchStatement"); CodeForStatementPosition(node); JumpTarget try_block; @@ -2043,12 +2052,12 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) { } -void CodeGenerator::VisitTryFinally(TryFinally* node) { +void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) { #ifdef DEBUG int original_height = frame_->height(); #endif VirtualFrame::SpilledScope spilled_scope; - Comment cmnt(masm_, "[ TryFinally"); + Comment cmnt(masm_, "[ TryFinallyStatement"); CodeForStatementPosition(node); // State: Used to keep track of reason for entering the finally diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index 1eb0932eb6..7b50b01049 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -147,6 +147,15 @@ class CodeGenerator: public AstVisitor { Handle