Version 3.9.15
Fix the heap profiler crash caused by memory layout changes between passes.
Fix Error.prototype.toString to throw TypeError. (issue 1980)
Fix double-rounding in strtod for MinGW. (issue 1062)
Fix corrupted snapshot serializaton on ia32. (Chromium issue v8/1985)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@10930 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 25563ed..0010c82 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -6560,15 +6560,15 @@
ASSERT(state_ == CompareIC::HEAP_NUMBERS);
Label generic_stub;
- Label unordered;
+ Label unordered, maybe_undefined1, maybe_undefined2;
Label miss;
__ and_(r2, r1, Operand(r0));
__ JumpIfSmi(r2, &generic_stub);
__ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE);
- __ b(ne, &miss);
+ __ b(ne, &maybe_undefined1);
__ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
- __ b(ne, &miss);
+ __ b(ne, &maybe_undefined2);
// Inlining the double comparison and falling back to the general compare
// stub if NaN is involved or VFP3 is unsupported.
@@ -6592,14 +6592,28 @@
__ mov(r0, Operand(LESS), LeaveCC, lt);
__ mov(r0, Operand(GREATER), LeaveCC, gt);
__ Ret();
-
- __ bind(&unordered);
}
+ __ bind(&unordered);
CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
__ bind(&generic_stub);
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ __ bind(&maybe_undefined1);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
+ __ b(ne, &miss);
+ __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
+ __ b(ne, &maybe_undefined2);
+ __ jmp(&unordered);
+ }
+
+ __ bind(&maybe_undefined2);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ CompareRoot(r1, Heap::kUndefinedValueRootIndex);
+ __ b(eq, &unordered);
+ }
+
__ bind(&miss);
GenerateMiss(masm);
}
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 506f9b2..6e18277 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -37,6 +37,19 @@
#define __ ACCESS_MASM(masm)
+TranscendentalFunction CreateTranscendentalFunction(
+ TranscendentalCache::Type type) {
+ switch (type) {
+ case TranscendentalCache::SIN: return &sin;
+ case TranscendentalCache::COS: return &cos;
+ case TranscendentalCache::TAN: return &tan;
+ case TranscendentalCache::LOG: return &log;
+ default: UNIMPLEMENTED();
+ }
+ return NULL;
+}
+
+
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 418e0c5..8639698 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -1004,6 +1004,16 @@
// We got a fixed array in register r0. Iterate through that.
Label non_proxy;
__ bind(&fixed_array);
+
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(
+ Handle<Object>(
+ Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
+ RecordTypeFeedbackCell(stmt->PrepareId(), cell);
+ __ LoadHeapObject(r1, cell);
+ __ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)));
+ __ str(r2, FieldMemOperand(r1, JSGlobalPropertyCell::kValueOffset));
+
__ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check
__ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 8654a3b..108a6de 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -440,7 +440,7 @@
void LChunk::MarkEmptyBlocks() {
- HPhase phase("L Mark empty blocks", this);
+ HPhase phase("L_Mark empty blocks", this);
for (int i = 0; i < graph()->blocks()->length(); ++i) {
HBasicBlock* block = graph()->blocks()->at(i);
int first = block->first_instruction_index();
@@ -552,7 +552,7 @@
LChunk* LChunkBuilder::Build() {
ASSERT(is_unused());
chunk_ = new(zone()) LChunk(info(), graph());
- HPhase phase("L Building chunk", chunk_);
+ HPhase phase("L_Building chunk", chunk_);
status_ = BUILDING;
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
for (int i = 0; i < blocks->length(); i++) {
@@ -1170,7 +1170,7 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
- if (op == kMathLog || op == kMathSin || op == kMathCos) {
+ if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* input = UseFixedDouble(instr->value(), d2);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
return MarkAsCall(DefineFixedDouble(result, d2), instr);
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index d03410b..fcbc90d 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -62,7 +62,7 @@
#define __ masm()->
bool LCodeGen::GenerateCode() {
- HPhase phase("Z Code generation", chunk());
+ HPhase phase("Z_Code generation", chunk());
ASSERT(is_unused());
status_ = GENERATING;
CpuFeatures::Scope scope1(VFP3);
diff --git a/src/ast.cc b/src/ast.cc
index b19fc35..65afd9a 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -520,13 +520,27 @@
LookupResult lookup(type->GetIsolate());
while (true) {
type->LookupInDescriptors(NULL, *name, &lookup);
- // For properties we know the target iff we have a constant function.
- if (lookup.IsFound() && lookup.IsProperty()) {
- if (lookup.type() == CONSTANT_FUNCTION) {
- target_ = Handle<JSFunction>(lookup.GetConstantFunctionFromMap(*type));
- return true;
+ if (lookup.IsFound()) {
+ switch (lookup.type()) {
+ case CONSTANT_FUNCTION:
+ // We surely know the target for a constant function.
+ target_ =
+ Handle<JSFunction>(lookup.GetConstantFunctionFromMap(*type));
+ return true;
+ case NORMAL:
+ case FIELD:
+ case CALLBACKS:
+ case HANDLER:
+ case INTERCEPTOR:
+ // We don't know the target.
+ return false;
+ case MAP_TRANSITION:
+ case ELEMENTS_TRANSITION:
+ case CONSTANT_TRANSITION:
+ case NULL_DESCRIPTOR:
+ // Perhaps something interesting is up in the prototype chain...
+ break;
}
- return false;
}
// If we reach the end of the prototype chain, we don't know the target.
if (!type->prototype()->IsJSObject()) return false;
diff --git a/src/codegen.h b/src/codegen.h
index 5360d3e..28a3006 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -84,6 +84,15 @@
namespace v8 {
namespace internal {
+// Results of the library implementation of transcendental functions may differ
+// from the one we use in our generated code. Therefore we use the same
+// generated code both in runtime and compiled code.
+typedef double (*TranscendentalFunction)(double x);
+
+TranscendentalFunction CreateTranscendentalFunction(
+ TranscendentalCache::Type type);
+
+
class ElementsTransitionGenerator : public AllStatic {
public:
static void GenerateSmiOnlyToObject(MacroAssembler* masm);
diff --git a/src/elements.cc b/src/elements.cc
index d951b0e..63bf090 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -173,12 +173,12 @@
if (len1 == 0) return to;
// Compute how many elements are not in other.
- int extra = 0;
+ uint32_t extra = 0;
for (uint32_t y = 0; y < len1; y++) {
- if (ElementsAccessorSubclass::HasElementAtIndexImpl(
- backing_store, y, holder, receiver)) {
- uint32_t key =
- ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+ uint32_t key =
+ ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+ if (ElementsAccessorSubclass::HasElementImpl(
+ backing_store, key, holder, receiver)) {
MaybeObject* maybe_value =
ElementsAccessorSubclass::GetImpl(backing_store, key,
holder, receiver);
@@ -210,12 +210,12 @@
}
}
// Fill in the extra values.
- int index = 0;
+ uint32_t index = 0;
for (uint32_t y = 0; y < len1; y++) {
- if (ElementsAccessorSubclass::HasElementAtIndexImpl(
- backing_store, y, holder, receiver)) {
- uint32_t key =
- ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+ uint32_t key =
+ ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+ if (ElementsAccessorSubclass::HasElementImpl(
+ backing_store, key, holder, receiver)) {
MaybeObject* maybe_value =
ElementsAccessorSubclass::GetImpl(backing_store, key,
holder, receiver);
@@ -241,23 +241,21 @@
BackingStoreClass::cast(backing_store));
}
- static bool HasElementAtIndexImpl(BackingStoreClass* backing_store,
- uint32_t index,
- JSObject* holder,
- Object* receiver) {
- uint32_t key =
- ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
+ static bool HasElementImpl(BackingStoreClass* backing_store,
+ uint32_t key,
+ JSObject* holder,
+ Object* receiver) {
MaybeObject* element =
ElementsAccessorSubclass::GetImpl(backing_store, key, holder, receiver);
return !element->IsTheHole();
}
- virtual bool HasElementAtIndex(FixedArrayBase* backing_store,
- uint32_t index,
- JSObject* holder,
- Object* receiver) {
- return ElementsAccessorSubclass::HasElementAtIndexImpl(
- BackingStoreClass::cast(backing_store), index, holder, receiver);
+ virtual bool HasElement(FixedArrayBase* backing_store,
+ uint32_t key,
+ JSObject* holder,
+ Object* receiver) {
+ return ElementsAccessorSubclass::HasElementImpl(
+ BackingStoreClass::cast(backing_store), key, holder, receiver);
}
static uint32_t GetKeyForIndexImpl(BackingStoreClass* backing_store,
@@ -266,7 +264,7 @@
}
virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
- uint32_t index) {
+ uint32_t index) {
return ElementsAccessorSubclass::GetKeyForIndexImpl(
BackingStoreClass::cast(backing_store), index);
}
@@ -441,11 +439,11 @@
return obj->GetHeap()->true_value();
}
- static bool HasElementAtIndexImpl(FixedDoubleArray* backing_store,
- uint32_t index,
- JSObject* holder,
- Object* receiver) {
- return !backing_store->is_the_hole(index);
+ static bool HasElementImpl(FixedDoubleArray* backing_store,
+ uint32_t key,
+ JSObject* holder,
+ Object* receiver) {
+ return !backing_store->is_the_hole(key);
}
};
@@ -484,6 +482,15 @@
// External arrays always ignore deletes.
return obj->GetHeap()->true_value();
}
+
+ static bool HasElementImpl(ExternalArray* backing_store,
+ uint32_t key,
+ JSObject* holder,
+ Object* receiver) {
+ uint32_t capacity =
+ ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
+ return key < capacity;
+ }
};
@@ -677,6 +684,14 @@
return obj->GetHeap()->the_hole_value();
}
+ static bool HasElementImpl(SeededNumberDictionary* backing_store,
+ uint32_t key,
+ JSObject* holder,
+ Object* receiver) {
+ return backing_store->FindEntry(key) !=
+ SeededNumberDictionary::kNotFound;
+ }
+
static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
uint32_t index) {
Object* key = dict->KeyAt(index);
@@ -696,7 +711,7 @@
uint32_t key,
JSObject* obj,
Object* receiver) {
- Object* probe = GetParameterMapArg(parameter_map, key);
+ Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
Context* context = Context::cast(parameter_map->get(0));
int context_index = Smi::cast(probe)->value();
@@ -735,7 +750,7 @@
uint32_t key,
JSReceiver::DeleteMode mode) {
FixedArray* parameter_map = FixedArray::cast(obj->elements());
- Object* probe = GetParameterMapArg(parameter_map, key);
+ Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
// TODO(kmillikin): We could check if this was the last aliased
// parameter, and revert to normal elements in that case. That
@@ -763,24 +778,27 @@
return index;
}
- static bool HasElementAtIndexImpl(FixedArray* parameter_map,
- uint32_t index,
- JSObject* holder,
- Object* receiver) {
- Object* probe = GetParameterMapArg(parameter_map, index);
+ static bool HasElementImpl(FixedArray* parameter_map,
+ uint32_t key,
+ JSObject* holder,
+ Object* receiver) {
+ Object* probe = GetParameterMapArg(holder, parameter_map, key);
if (!probe->IsTheHole()) {
return true;
} else {
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
- return !accessor->Get(arguments, index, holder, receiver)->IsTheHole();
+ return !accessor->Get(arguments, key, holder, receiver)->IsTheHole();
}
}
private:
- static Object* GetParameterMapArg(FixedArray* parameter_map,
+ static Object* GetParameterMapArg(JSObject* holder,
+ FixedArray* parameter_map,
uint32_t key) {
- uint32_t length = parameter_map->length();
+ uint32_t length = holder->IsJSArray()
+ ? Smi::cast(JSArray::cast(holder)->length())->value()
+ : parameter_map->length();
return key < (length - 2 )
? parameter_map->get(key + 2)
: parameter_map->GetHeap()->the_hole_value();
diff --git a/src/elements.h b/src/elements.h
index a2a184d..615d5f9 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -66,6 +66,11 @@
uint32_t key,
JSReceiver::DeleteMode mode) = 0;
+ virtual bool HasElement(FixedArrayBase* backing_store,
+ uint32_t key,
+ JSObject* holder,
+ Object* receiver) = 0;
+
virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
FixedArray* to,
JSObject* holder,
@@ -86,19 +91,14 @@
virtual uint32_t GetCapacity(FixedArrayBase* backing_store) = 0;
- virtual bool HasElementAtIndex(FixedArrayBase* backing_store,
- uint32_t index,
- JSObject* holder,
- Object* receiver) = 0;
-
- // Element handlers distinguish between indexes and keys when the manipulate
+ // Element handlers distinguish between indexes and keys when they manipulate
// elements. Indexes refer to elements in terms of their location in the
- // underlying storage's backing store representation, and are between 0
+ // underlying storage's backing store representation, and are between 0 and
// GetCapacity. Keys refer to elements in terms of the value that would be
- // specific in JavaScript to access the element. In most implementations, keys
- // are equivalent to indexes, and GetKeyForIndex returns the same value it is
- // passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps the
- // index to a key using the KeyAt method on the NumberDictionary.
+ // specified in JavaScript to access the element. In most implementations,
+ // keys are equivalent to indexes, and GetKeyForIndex returns the same value
+ // it is passed. In the NumberDictionary ElementsAccessor, GetKeyForIndex maps
+ // the index to a key using the KeyAt method on the NumberDictionary.
virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
uint32_t index) = 0;
diff --git a/src/globals.h b/src/globals.h
index 9f13780..e53cc81 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -175,27 +175,27 @@
// than defining __STDC_CONSTANT_MACROS before including <stdint.h>, and it
// works on compilers that don't have it (like MSVC).
#if V8_HOST_ARCH_64_BIT
-#ifdef _MSC_VER
+#if defined(_MSC_VER)
#define V8_UINT64_C(x) (x ## UI64)
#define V8_INT64_C(x) (x ## I64)
#define V8_INTPTR_C(x) (x ## I64)
#define V8_PTR_PREFIX "ll"
-#else // _MSC_VER
+#elif defined(__MINGW64__)
+#define V8_UINT64_C(x) (x ## ULL)
+#define V8_INT64_C(x) (x ## LL)
+#define V8_INTPTR_C(x) (x ## LL)
+#define V8_PTR_PREFIX "I64"
+#else
#define V8_UINT64_C(x) (x ## UL)
#define V8_INT64_C(x) (x ## L)
#define V8_INTPTR_C(x) (x ## L)
#define V8_PTR_PREFIX "l"
-#endif // _MSC_VER
+#endif
#else // V8_HOST_ARCH_64_BIT
#define V8_INTPTR_C(x) (x)
#define V8_PTR_PREFIX ""
#endif // V8_HOST_ARCH_64_BIT
-#ifdef __MINGW64__
-#undef V8_PTR_PREFIX
-#define V8_PTR_PREFIX "I64"
-#endif // __MINGW64__
-
// The following macro works on both 32 and 64-bit platforms.
// Usage: instead of writing 0x1234567890123456
// write V8_2PART_UINT64_C(0x12345678,90123456);
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 81ed448..706d288 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -32,6 +32,7 @@
#include "isolate.h"
#include "list-inl.h"
#include "objects.h"
+#include "platform.h"
#include "v8-counters.h"
#include "store-buffer.h"
#include "store-buffer-inl.h"
@@ -658,15 +659,15 @@
case ATAN:
return atan(input);
case COS:
- return cos(input);
+ return fast_cos(input);
case EXP:
return exp(input);
case LOG:
- return log(input);
+ return fast_log(input);
case SIN:
- return sin(input);
+ return fast_sin(input);
case TAN:
- return tan(input);
+ return fast_tan(input);
default:
return 0.0; // Never happens.
}
diff --git a/src/heap.cc b/src/heap.cc
index e0b1e50..82e0965 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1909,11 +1909,10 @@
MaybeObject* Heap::AllocateCodeCache() {
- Object* result;
- { MaybeObject* maybe_result = AllocateStruct(CODE_CACHE_TYPE);
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ CodeCache* code_cache;
+ { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
+ if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
}
- CodeCache* code_cache = CodeCache::cast(result);
code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
return code_cache;
@@ -1926,22 +1925,20 @@
MaybeObject* Heap::AllocateAccessorPair() {
- Object* result;
- { MaybeObject* maybe_result = AllocateStruct(ACCESSOR_PAIR_TYPE);
- if (!maybe_result->ToObject(&result)) return maybe_result;
+ AccessorPair* accessors;
+ { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
+ if (!maybe_accessors->To(&accessors)) return maybe_accessors;
}
- AccessorPair* accessors = AccessorPair::cast(result);
- // Later we will have to distinguish between undefined and the hole...
- // accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
- // accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
+ accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
+ accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
return accessors;
}
MaybeObject* Heap::AllocateTypeFeedbackInfo() {
TypeFeedbackInfo* info;
- { MaybeObject* maybe_result = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
- if (!maybe_result->To(&info)) return maybe_result;
+ { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
+ if (!maybe_info->To(&info)) return maybe_info;
}
info->set_ic_total_count(0);
info->set_ic_with_typeinfo_count(0);
@@ -1953,8 +1950,8 @@
MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
AliasedArgumentsEntry* entry;
- { MaybeObject* maybe_result = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
- if (!maybe_result->To(&entry)) return maybe_result;
+ { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
+ if (!maybe_entry->To(&entry)) return maybe_entry;
}
entry->set_aliased_context_slot(aliased_context_slot);
return entry;
@@ -6921,14 +6918,18 @@
// pieces and initialize size, owner and flags field of every piece.
// If FromAnyPointerAddress encounters a slot that belongs to one of
// these smaller pieces it will treat it as a slot on a normal Page.
+ Address chunk_end = chunk->address() + chunk->size();
MemoryChunk* inner = MemoryChunk::FromAddress(
chunk->address() + Page::kPageSize);
- MemoryChunk* inner_last = MemoryChunk::FromAddress(
- chunk->address() + chunk->size() - 1);
+ MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
while (inner <= inner_last) {
// Size of a large chunk is always a multiple of
// OS::AllocateAlignment() so there is always
// enough space for a fake MemoryChunk header.
+ Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
+ // Guard against overflow.
+ if (area_end < inner->address()) area_end = chunk_end;
+ inner->SetArea(inner->address(), area_end);
inner->set_size(Page::kPageSize);
inner->set_owner(lo_space());
inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index cbe1fb5..1069684 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1479,7 +1479,22 @@
void HCompareIDAndBranch::SetInputRepresentation(Representation r) {
input_representation_ = r;
if (r.IsDouble()) {
- SetFlag(kDeoptimizeOnUndefined);
+ // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, ===
+ // and !=) have special handling of undefined, e.g. undefined == undefined
+ // is 'true'. Relational comparisons have a different semantic, first
+ // calling ToPrimitive() on their arguments. The standard Crankshaft
+ // tagged-to-double conversion to ensure the HCompareIDAndBranch's inputs
+ // are doubles caused 'undefined' to be converted to NaN. That's compatible
+ // out-of-the box with ordered relational comparisons (<, >, <=,
+ // >=). However, for equality comparisons (and for 'in' and 'instanceof'),
+ // it is not consistent with the spec. For example, it would cause undefined
+ // == undefined (should be true) to be evaluated as NaN == NaN
+ // (false). Therefore, any comparisons other than ordered relational
+ // comparisons must cause a deopt when one of their arguments is undefined.
+ // See also v8:1434
+ if (!Token::IsOrderedRelationalCompareOp(token_)) {
+ SetFlag(kDeoptimizeOnUndefined);
+ }
} else {
ASSERT(r.IsInteger32());
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index eb0e0fd..a05fc77 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -1886,6 +1886,7 @@
case kMathLog:
case kMathSin:
case kMathCos:
+ case kMathTan:
set_representation(Representation::Double());
break;
default:
@@ -1916,6 +1917,7 @@
case kMathLog:
case kMathSin:
case kMathCos:
+ case kMathTan:
return Representation::Double();
case kMathAbs:
return representation();
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index cbcf32f..b731bc4 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -730,7 +730,7 @@
void HGraph::Canonicalize() {
if (!FLAG_use_canonicalizing) return;
- HPhase phase("H Canonicalize", this);
+ HPhase phase("H_Canonicalize", this);
for (int i = 0; i < blocks()->length(); ++i) {
HInstruction* instr = blocks()->at(i)->first();
while (instr != NULL) {
@@ -743,7 +743,7 @@
void HGraph::OrderBlocks() {
- HPhase phase("H Block ordering");
+ HPhase phase("H_Block ordering");
BitVector visited(blocks_.length(), zone());
ZoneList<HBasicBlock*> reverse_result(8);
@@ -805,7 +805,7 @@
void HGraph::AssignDominators() {
- HPhase phase("H Assign dominators", this);
+ HPhase phase("H_Assign dominators", this);
for (int i = 0; i < blocks_.length(); ++i) {
HBasicBlock* block = blocks_[i];
if (block->IsLoopHeader()) {
@@ -824,7 +824,7 @@
// Mark all blocks that are dominated by an unconditional soft deoptimize to
// prevent code motion across those blocks.
void HGraph::PropagateDeoptimizingMark() {
- HPhase phase("H Propagate deoptimizing mark", this);
+ HPhase phase("H_Propagate deoptimizing mark", this);
MarkAsDeoptimizingRecursively(entry_block());
}
@@ -837,7 +837,7 @@
}
void HGraph::EliminateRedundantPhis() {
- HPhase phase("H Redundant phi elimination", this);
+ HPhase phase("H_Redundant phi elimination", this);
// Worklist of phis that can potentially be eliminated. Initialized with
// all phi nodes. When elimination of a phi node modifies another phi node
@@ -871,7 +871,7 @@
void HGraph::EliminateUnreachablePhis() {
- HPhase phase("H Unreachable phi elimination", this);
+ HPhase phase("H_Unreachable phi elimination", this);
// Initialize worklist.
ZoneList<HPhi*> phi_list(blocks_.length());
@@ -1010,7 +1010,7 @@
void HRangeAnalysis::Analyze() {
- HPhase phase("H Range analysis", graph_);
+ HPhase phase("H_Range analysis", graph_);
Analyze(graph_->entry_block());
}
@@ -1831,7 +1831,7 @@
void HInferRepresentation::Analyze() {
- HPhase phase("H Infer representations", graph_);
+ HPhase phase("H_Infer representations", graph_);
// (1) Initialize bit vectors and count real uses. Each phi gets a
// bit-vector of length <number of phis>.
@@ -1910,7 +1910,7 @@
void HGraph::InitializeInferredTypes() {
- HPhase phase("H Inferring types", this);
+ HPhase phase("H_Inferring types", this);
InitializeInferredTypes(0, this->blocks_.length() - 1);
}
@@ -2047,8 +2047,7 @@
void HGraph::InsertRepresentationChanges() {
- HPhase phase("H Insert representation changes", this);
-
+ HPhase phase("H_Representation changes", this);
// Compute truncation flag for phis: Initially assume that all
// int32-phis allow truncation and iteratively remove the ones that
@@ -2104,7 +2103,7 @@
void HGraph::MarkDeoptimizeOnUndefined() {
- HPhase phase("H MarkDeoptimizeOnUndefined", this);
+ HPhase phase("H_MarkDeoptimizeOnUndefined", this);
// Compute DeoptimizeOnUndefined flag for phis.
// Any phi that can reach a use with DeoptimizeOnUndefined set must
// have DeoptimizeOnUndefined set. Currently only HCompareIDAndBranch, with
@@ -2430,7 +2429,7 @@
if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info());
{
- HPhase phase("H Block building");
+ HPhase phase("H_Block building");
current_block_ = graph()->entry_block();
Scope* scope = info()->scope();
@@ -2515,7 +2514,7 @@
// Perform common subexpression elimination and loop-invariant code motion.
if (FLAG_use_gvn) {
- HPhase phase("H Global value numbering", graph());
+ HPhase phase("H_Global value numbering", graph());
HGlobalValueNumberer gvn(graph(), info());
bool removed_side_effects = gvn.Analyze();
// Trigger a second analysis pass to further eliminate duplicate values that
@@ -2548,7 +2547,7 @@
void HGraph::ReplaceCheckedValues() {
- HPhase phase("H Replace checked values", this);
+ HPhase phase("H_Replace checked values", this);
for (int i = 0; i < blocks()->length(); ++i) {
HInstruction* instr = blocks()->at(i)->first();
while (instr != NULL) {
@@ -3274,6 +3273,10 @@
return Bailout("ForInStatement optimization is disabled");
}
+ if (!oracle()->IsForInFastCase(stmt)) {
+ return Bailout("ForInStatement is not fast case");
+ }
+
if (!stmt->each()->IsVariableProxy() ||
!stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
return Bailout("ForInStatement with non-local each variable");
@@ -5416,6 +5419,7 @@
case kMathLog:
case kMathSin:
case kMathCos:
+ case kMathTan:
if (expr->arguments()->length() == 1) {
HValue* argument = Pop();
HValue* context = environment()->LookupContext();
@@ -5476,6 +5480,7 @@
case kMathLog:
case kMathSin:
case kMathCos:
+ case kMathTan:
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr, receiver, receiver_map, true);
HValue* argument = Pop();
@@ -7687,7 +7692,7 @@
// builtin function, pass undefined as the receiver for function
// calls (instead of the global receiver).
if ((target->shared()->native() || !function->is_classic_mode()) &&
- call_kind == CALL_AS_FUNCTION) {
+ call_kind == CALL_AS_FUNCTION && !is_construct) {
inner->SetValueAt(0, undefined);
}
inner->SetValueAt(arity + 1, LookupContext());
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 864e76c..5b6f687 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -2510,7 +2510,7 @@
__ fld_d(Operand(esp, 0));
__ add(esp, Immediate(kDoubleSize));
}
- GenerateOperation(masm);
+ GenerateOperation(masm, type_);
__ mov(Operand(ecx, 0), ebx);
__ mov(Operand(ecx, kIntSize), edx);
__ mov(Operand(ecx, 2 * kIntSize), eax);
@@ -2526,7 +2526,7 @@
__ sub(esp, Immediate(kDoubleSize));
__ movdbl(Operand(esp, 0), xmm1);
__ fld_d(Operand(esp, 0));
- GenerateOperation(masm);
+ GenerateOperation(masm, type_);
__ fstp_d(Operand(esp, 0));
__ movdbl(xmm1, Operand(esp, 0));
__ add(esp, Immediate(kDoubleSize));
@@ -2578,14 +2578,15 @@
}
-void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
+void TranscendentalCacheStub::GenerateOperation(
+ MacroAssembler* masm, TranscendentalCache::Type type) {
// Only free register is edi.
// Input value is on FP stack, and also in ebx/edx.
// Input value is possibly in xmm1.
// Address of result (a newly allocated HeapNumber) may be in eax.
- if (type_ == TranscendentalCache::SIN ||
- type_ == TranscendentalCache::COS ||
- type_ == TranscendentalCache::TAN) {
+ if (type == TranscendentalCache::SIN ||
+ type == TranscendentalCache::COS ||
+ type == TranscendentalCache::TAN) {
// Both fsin and fcos require arguments in the range +/-2^63 and
// return NaN for infinities and NaN. They can share all code except
// the actual fsin/fcos operation.
@@ -2649,7 +2650,7 @@
// FPU Stack: input % 2*pi
__ bind(&in_range);
- switch (type_) {
+ switch (type) {
case TranscendentalCache::SIN:
__ fsin();
break;
@@ -2667,7 +2668,7 @@
}
__ bind(&done);
} else {
- ASSERT(type_ == TranscendentalCache::LOG);
+ ASSERT(type == TranscendentalCache::LOG);
__ fldln2();
__ fxch();
__ fyl2x();
@@ -6572,16 +6573,16 @@
ASSERT(state_ == CompareIC::HEAP_NUMBERS);
Label generic_stub;
- Label unordered;
+ Label unordered, maybe_undefined1, maybe_undefined2;
Label miss;
__ mov(ecx, edx);
__ and_(ecx, eax);
__ JumpIfSmi(ecx, &generic_stub, Label::kNear);
__ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
- __ j(not_equal, &miss, Label::kNear);
+ __ j(not_equal, &maybe_undefined1, Label::kNear);
__ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
- __ j(not_equal, &miss, Label::kNear);
+ __ j(not_equal, &maybe_undefined2, Label::kNear);
// Inlining the double comparison and falling back to the general compare
// stub if NaN is involved or SS2 or CMOV is unsupported.
@@ -6607,14 +6608,28 @@
__ mov(ecx, Immediate(Smi::FromInt(-1)));
__ cmov(below, eax, ecx);
__ ret(0);
-
- __ bind(&unordered);
}
+ __ bind(&unordered);
CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
__ bind(&generic_stub);
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+ __ bind(&maybe_undefined1);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value()));
+ __ j(not_equal, &miss);
+ __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
+ __ j(not_equal, &maybe_undefined2, Label::kNear);
+ __ jmp(&unordered);
+ }
+
+ __ bind(&maybe_undefined2);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value()));
+ __ j(equal, &unordered);
+ }
+
__ bind(&miss);
GenerateMiss(masm);
}
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index 4d23c3a..803a711 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -49,6 +49,8 @@
ArgumentType argument_type)
: type_(type), argument_type_(argument_type) {}
void Generate(MacroAssembler* masm);
+ static void GenerateOperation(MacroAssembler* masm,
+ TranscendentalCache::Type type);
private:
TranscendentalCache::Type type_;
ArgumentType argument_type_;
@@ -56,7 +58,6 @@
Major MajorKey() { return TranscendentalCache; }
int MinorKey() { return type_ | argument_type_; }
Runtime::FunctionId RuntimeFunction();
- void GenerateOperation(MacroAssembler* masm);
};
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 3e085a2..de6901f 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_IA32)
#include "codegen.h"
+#include "heap.h"
#include "macro-assembler.h"
namespace v8 {
@@ -55,6 +56,53 @@
#define __ masm.
+
+TranscendentalFunction CreateTranscendentalFunction(
+ TranscendentalCache::Type type) {
+ size_t actual_size;
+ // Allocate buffer in executable space.
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
+ &actual_size,
+ true));
+ if (buffer == NULL) {
+ // Fallback to library function if function cannot be created.
+ switch (type) {
+ case TranscendentalCache::SIN: return &sin;
+ case TranscendentalCache::COS: return &cos;
+ case TranscendentalCache::TAN: return &tan;
+ case TranscendentalCache::LOG: return &log;
+ default: UNIMPLEMENTED();
+ }
+ }
+
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+ // esp[1 * kPointerSize]: raw double input
+ // esp[0 * kPointerSize]: return address
+ // Move double input into registers.
+
+ __ push(ebx);
+ __ push(edx);
+ __ push(edi);
+ __ fld_d(Operand(esp, 4 * kPointerSize));
+ __ mov(ebx, Operand(esp, 4 * kPointerSize));
+ __ mov(edx, Operand(esp, 5 * kPointerSize));
+ TranscendentalCacheStub::GenerateOperation(&masm, type);
+ // The return value is expected to be on ST(0) of the FPU stack.
+ __ pop(edi);
+ __ pop(edx);
+ __ pop(ebx);
+ __ Ret();
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+ ASSERT(desc.reloc_size == 0);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+ return FUNCTION_CAST<TranscendentalFunction>(buffer);
+}
+
+
static void MemCopyWrapper(void* dest, const void* src, size_t size) {
memcpy(dest, src, size);
}
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 0b7c7fd..86ca138 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1033,6 +1033,16 @@
// We got a fixed array in register eax. Iterate through that.
Label non_proxy;
__ bind(&fixed_array);
+
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(
+ Handle<Object>(
+ Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
+ RecordTypeFeedbackCell(stmt->PrepareId(), cell);
+ __ LoadHeapObject(ebx, cell);
+ __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset),
+ Immediate(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)));
+
__ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
__ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 13b788c..6ddc024 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -67,7 +67,7 @@
#define __ masm()->
bool LCodeGen::GenerateCode() {
- HPhase phase("Z Code generation", chunk());
+ HPhase phase("Z_Code generation", chunk());
ASSERT(is_unused());
status_ = GENERATING;
CpuFeatures::Scope scope(SSE2);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 94e992f..7587016 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -388,7 +388,7 @@
void LChunk::MarkEmptyBlocks() {
- HPhase phase("L Mark empty blocks", this);
+ HPhase phase("L_Mark empty blocks", this);
for (int i = 0; i < graph()->blocks()->length(); ++i) {
HBasicBlock* block = graph()->blocks()->at(i);
int first = block->first_instruction_index();
@@ -551,7 +551,7 @@
LChunk* LChunkBuilder::Build() {
ASSERT(is_unused());
chunk_ = new(zone()) LChunk(info(), graph());
- HPhase phase("L Building chunk", chunk_);
+ HPhase phase("L_Building chunk", chunk_);
status_ = BUILDING;
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
for (int i = 0; i < blocks->length(); i++) {
@@ -1195,7 +1195,7 @@
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
input);
return DefineSameAsFirst(result);
- } else if (op == kMathSin || op == kMathCos) {
+ } else if (op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* input = UseFixedDouble(instr->value(), xmm1);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index 2c9b60c..e718879 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -287,7 +287,7 @@
void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
Label fallthrough;
__ cmp(edi, Operand(backtrack_stackpointer(), 0));
- __ j(not_equal, &fallthrough);
+ __ j(not_equal, &fallthrough, Label::kNear);
__ add(backtrack_stackpointer(), Immediate(kPointerSize)); // Pop.
BranchOrBacktrack(no_condition, on_equal);
__ bind(&fallthrough);
@@ -328,19 +328,19 @@
__ bind(&loop);
__ movzx_b(eax, Operand(edi, 0));
__ cmpb_al(Operand(edx, 0));
- __ j(equal, &loop_increment);
+ __ j(equal, &loop_increment, Label::kNear);
// Mismatch, try case-insensitive match (converting letters to lower-case).
__ or_(eax, 0x20); // Convert match character to lower-case.
__ lea(ecx, Operand(eax, -'a'));
__ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter?
- __ j(above, &fail);
+ __ j(above, &fail, Label::kNear);
// Also convert capture character.
__ movzx_b(ecx, Operand(edx, 0));
__ or_(ecx, 0x20);
__ cmp(eax, ecx);
- __ j(not_equal, &fail);
+ __ j(not_equal, &fail, Label::kNear);
__ bind(&loop_increment);
// Increment pointers into match and capture strings.
@@ -349,7 +349,7 @@
// Compare to end of match, and loop if not done.
__ cmp(edi, ebx);
__ j(below, &loop);
- __ jmp(&success);
+ __ jmp(&success, Label::kNear);
__ bind(&fail);
// Restore original values before failing.
@@ -457,14 +457,14 @@
__ movzx_w(eax, Operand(edx, 0));
__ cmpw_ax(Operand(ebx, 0));
}
- __ j(not_equal, &fail);
+ __ j(not_equal, &fail, Label::kNear);
// Increment pointers into capture and match string.
__ add(edx, Immediate(char_size()));
__ add(ebx, Immediate(char_size()));
// Check if we have reached end of match area.
__ cmp(ebx, ecx);
__ j(below, &loop);
- __ jmp(&success);
+ __ jmp(&success, Label::kNear);
__ bind(&fail);
// Restore backtrack stackpointer.
@@ -542,7 +542,7 @@
// ASCII space characters are '\t'..'\r' and ' '.
Label success;
__ cmp(current_character(), ' ');
- __ j(equal, &success);
+ __ j(equal, &success, Label::kNear);
// Check range 0x09..0x0d
__ lea(eax, Operand(current_character(), -'\t'));
__ cmp(eax, '\r' - '\t');
@@ -611,7 +611,7 @@
if (mode_ != ASCII) {
// Table is 128 entries, so all ASCII characters can be tested.
__ cmp(current_character(), Immediate('z'));
- __ j(above, &done);
+ __ j(above, &done, Label::kNear);
}
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
ExternalReference word_map = ExternalReference::re_word_character_map();
@@ -695,11 +695,11 @@
__ mov(ecx, esp);
__ sub(ecx, Operand::StaticVariable(stack_limit));
// Handle it if the stack pointer is already below the stack limit.
- __ j(below_equal, &stack_limit_hit);
+ __ j(below_equal, &stack_limit_hit, Label::kNear);
// Check if there is room for the variable number of registers above
// the stack limit.
__ cmp(ecx, num_registers_ * kPointerSize);
- __ j(above_equal, &stack_ok);
+ __ j(above_equal, &stack_ok, Label::kNear);
// Exit with OutOfMemory exception. There is not enough space on the stack
// for our working registers.
__ mov(eax, EXCEPTION);
@@ -764,7 +764,7 @@
// Load previous char as initial value of current-character.
Label at_start;
__ cmp(Operand(ebp, kStartIndex), Immediate(0));
- __ j(equal, &at_start);
+ __ j(equal, &at_start, Label::kNear);
LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
__ jmp(&start_label_);
__ bind(&at_start);
@@ -1235,7 +1235,7 @@
ExternalReference stack_limit =
ExternalReference::address_of_stack_limit(masm_->isolate());
__ cmp(esp, Operand::StaticVariable(stack_limit));
- __ j(above, &no_preempt);
+ __ j(above, &no_preempt, Label::kNear);
SafeCall(&check_preempt_label_);
@@ -1248,7 +1248,7 @@
ExternalReference stack_limit =
ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
__ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
- __ j(above, &no_stack_overflow);
+ __ j(above, &no_stack_overflow, Label::kNear);
SafeCall(&stack_overflow_label_);
diff --git a/src/ic.cc b/src/ic.cc
index 9bea13b..88d8a84 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -2482,6 +2482,14 @@
case UNINITIALIZED:
if (x->IsSmi() && y->IsSmi()) return SMIS;
if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS;
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ // Ordered comparisons treat undefined as NaN, so the
+ // HEAP_NUMBER stub will do the right thing.
+ if ((x->IsNumber() && y->IsUndefined()) ||
+ (y->IsNumber() && x->IsUndefined())) {
+ return HEAP_NUMBERS;
+ }
+ }
if (!Token::IsEqualityOp(op_)) return GENERIC;
if (x->IsSymbol() && y->IsSymbol()) return SYMBOLS;
if (x->IsString() && y->IsString()) return STRINGS;
diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc
index a15435c..83805dc 100644
--- a/src/lithium-allocator.cc
+++ b/src/lithium-allocator.cc
@@ -1105,7 +1105,7 @@
void LAllocator::MeetRegisterConstraints() {
- HPhase phase("L Register constraints", chunk_);
+ HPhase phase("L_Register constraints", chunk_);
first_artificial_register_ = next_virtual_register_;
const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
for (int i = 0; i < blocks->length(); ++i) {
@@ -1117,7 +1117,7 @@
void LAllocator::ResolvePhis() {
- HPhase phase("L Resolve phis", chunk_);
+ HPhase phase("L_Resolve phis", chunk_);
// Process the blocks in reverse order.
const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
@@ -1207,7 +1207,7 @@
void LAllocator::ConnectRanges() {
- HPhase phase("L Connect ranges", this);
+ HPhase phase("L_Connect ranges", this);
for (int i = 0; i < live_ranges()->length(); ++i) {
LiveRange* first_range = live_ranges()->at(i);
if (first_range == NULL || first_range->parent() != NULL) continue;
@@ -1247,7 +1247,7 @@
void LAllocator::ResolveControlFlow() {
- HPhase phase("L Resolve control flow", this);
+ HPhase phase("L_Resolve control flow", this);
const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
for (int block_id = 1; block_id < blocks->length(); ++block_id) {
HBasicBlock* block = blocks->at(block_id);
@@ -1268,7 +1268,7 @@
void LAllocator::BuildLiveRanges() {
- HPhase phase("L Build live ranges", this);
+ HPhase phase("L_Build live ranges", this);
InitializeLivenessAnalysis();
// Process the blocks in reverse order.
const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
@@ -1373,7 +1373,7 @@
void LAllocator::PopulatePointerMaps() {
- HPhase phase("L Populate pointer maps", this);
+ HPhase phase("L_Populate pointer maps", this);
const ZoneList<LPointerMap*>* pointer_maps = chunk_->pointer_maps();
ASSERT(SafePointsAreInOrder());
@@ -1492,14 +1492,14 @@
void LAllocator::AllocateGeneralRegisters() {
- HPhase phase("L Allocate general registers", this);
+ HPhase phase("L_Allocate general registers", this);
num_registers_ = Register::kNumAllocatableRegisters;
AllocateRegisters();
}
void LAllocator::AllocateDoubleRegisters() {
- HPhase phase("L Allocate double registers", this);
+ HPhase phase("L_Allocate double registers", this);
num_registers_ = DoubleRegister::kNumAllocatableRegisters;
mode_ = DOUBLE_REGISTERS;
AllocateRegisters();
diff --git a/src/messages.js b/src/messages.js
index e641133..0afc037 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -210,7 +210,7 @@
"no_input_to_regexp", ["No input to ", "%0"],
"invalid_json", ["String '", "%0", "' is not valid JSON"],
"circular_structure", ["Converting circular structure to JSON"],
- "obj_ctor_property_non_object", ["Object.", "%0", " called on non-object"],
+ "called_on_non_object", ["%0", " called on non-object"],
"called_on_null_or_undefined", ["%0", " called on null or undefined"],
"array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"],
"object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"],
@@ -533,6 +533,13 @@
if (this.name) {
return this.name;
}
+
+ // The result is cached as on long scripts it takes noticable time to search
+ // for the sourceURL.
+ if (this.hasCachedNameOrSourceURL)
+ return this.cachedNameOrSourceURL;
+ this.hasCachedNameOrSourceURL = true;
+
// TODO(608): the spaces in a regexp below had to be escaped as \040
// because this file is being processed by js2c whose handling of spaces
// in regexps is broken. Also, ['"] are excluded from allowed URLs to
@@ -541,6 +548,7 @@
// the scanner/parser.
var source = ToString(this.source);
var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
+ this.cachedNameOrSourceURL = this.name;
if (sourceUrlPos > 4) {
var sourceUrlPattern =
/\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
@@ -551,15 +559,17 @@
var match =
%_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
if (match) {
- return SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
+ this.cachedNameOrSourceURL =
+ SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
}
}
- return this.name;
+ return this.cachedNameOrSourceURL;
}
SetUpLockedPrototype(Script,
- $Array("source", "name", "line_ends", "line_offset", "column_offset"),
+ $Array("source", "name", "line_ends", "line_offset", "column_offset",
+ "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
$Array(
"lineFromPosition", ScriptLineFromPosition,
"locationFromPosition", ScriptLocationFromPosition,
@@ -1190,9 +1200,8 @@
}
function ErrorToString() {
- if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
- throw MakeTypeError("called_on_null_or_undefined",
- ["Error.prototype.toString"]);
+ if (!IS_SPEC_OBJECT(this)) {
+ throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
}
try {
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 4717847..a928dc0 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -6785,15 +6785,15 @@
ASSERT(state_ == CompareIC::HEAP_NUMBERS);
Label generic_stub;
- Label unordered;
+ Label unordered, maybe_undefined1, maybe_undefined2;
Label miss;
__ And(a2, a1, Operand(a0));
__ JumpIfSmi(a2, &generic_stub);
__ GetObjectType(a0, a2, a2);
- __ Branch(&miss, ne, a2, Operand(HEAP_NUMBER_TYPE));
+ __ Branch(&maybe_undefined1, ne, a2, Operand(HEAP_NUMBER_TYPE));
__ GetObjectType(a1, a2, a2);
- __ Branch(&miss, ne, a2, Operand(HEAP_NUMBER_TYPE));
+ __ Branch(&maybe_undefined2, ne, a2, Operand(HEAP_NUMBER_TYPE));
// Inlining the double comparison and falling back to the general compare
// stub if NaN is involved or FPU is unsupported.
@@ -6825,14 +6825,29 @@
__ bind(&fpu_lt);
__ Ret(USE_DELAY_SLOT);
__ li(v0, Operand(LESS)); // In delay slot.
-
- __ bind(&unordered);
}
+ __ bind(&unordered);
+
CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0);
__ bind(&generic_stub);
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ __ bind(&maybe_undefined1);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+ __ Branch(&miss, ne, a0, Operand(at));
+ __ GetObjectType(a1, a2, a2);
+ __ Branch(&maybe_undefined2, ne, a2, Operand(HEAP_NUMBER_TYPE));
+ __ jmp(&unordered);
+ }
+
+ __ bind(&maybe_undefined2);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+ __ Branch(&unordered, eq, a1, Operand(at));
+ }
+
__ bind(&miss);
GenerateMiss(masm);
}
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index d7bddaf..8cbb771 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -37,6 +37,19 @@
#define __ ACCESS_MASM(masm)
+TranscendentalFunction CreateTranscendentalFunction(
+ TranscendentalCache::Type type) {
+ switch (type) {
+ case TranscendentalCache::SIN: return &sin;
+ case TranscendentalCache::COS: return &cos;
+ case TranscendentalCache::TAN: return &tan;
+ case TranscendentalCache::LOG: return &log;
+ default: UNIMPLEMENTED();
+ }
+ return NULL;
+}
+
+
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index 2dd0522..b6f019f 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -1571,7 +1571,10 @@
// Check that the array has fast properties, otherwise the length
// property might have been redefined.
- // TODO(mstarzinger): Port this check to MIPS.
+ __ lw(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
+ __ lw(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
+ __ LoadRoot(at, Heap::kHashTableMapRootIndex);
+ __ Branch(&miss, eq, scratch, Operand(at));
// Check that value is a smi.
__ JumpIfNotSmi(value, &miss);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index a463cd3..c8d37b6 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -62,7 +62,7 @@
#define __ masm()->
bool LCodeGen::GenerateCode() {
- HPhase phase("Z Code generation", chunk());
+ HPhase phase("Z_Code generation", chunk());
ASSERT(is_unused());
status_ = GENERATING;
CpuFeatures::Scope scope(FPU);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 2607522..1c4e1da 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -440,7 +440,7 @@
void LChunk::MarkEmptyBlocks() {
- HPhase phase("L Mark empty blocks", this);
+ HPhase phase("L_Mark empty blocks", this);
for (int i = 0; i < graph()->blocks()->length(); ++i) {
HBasicBlock* block = graph()->blocks()->at(i);
int first = block->first_instruction_index();
@@ -552,7 +552,7 @@
LChunk* LChunkBuilder::Build() {
ASSERT(is_unused());
chunk_ = new(zone()) LChunk(info(), graph());
- HPhase phase("L Building chunk", chunk_);
+ HPhase phase("L_Building chunk", chunk_);
status_ = BUILDING;
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
for (int i = 0; i < blocks->length(); i++) {
@@ -1169,7 +1169,7 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
- if (op == kMathLog || op == kMathSin || op == kMathCos) {
+ if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* input = UseFixedDouble(instr->value(), f4);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
return MarkAsCall(DefineFixedDouble(result, f4), instr);
diff --git a/src/objects-inl.h b/src/objects-inl.h
index bc6217b..176be9b 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1988,7 +1988,8 @@
bool DescriptorArray::IsProperty(int descriptor_number) {
- return IsRealProperty(GetType(descriptor_number));
+ Entry entry(this, descriptor_number);
+ return IsPropertyDescriptor(&entry);
}
diff --git a/src/objects.cc b/src/objects.cc
index bc0a82e..721681b 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -4367,7 +4367,7 @@
static bool UpdateGetterSetterInDictionary(
SeededNumberDictionary* dictionary,
uint32_t index,
- bool is_getter,
+ AccessorComponent component,
Object* fun,
PropertyAttributes attributes) {
int entry = dictionary->FindEntry(index);
@@ -4381,7 +4381,7 @@
dictionary->DetailsAtPut(entry,
PropertyDetails(attributes, CALLBACKS, index));
}
- AccessorPair::cast(result)->set(is_getter, fun);
+ AccessorPair::cast(result)->set(component, fun);
return true;
}
}
@@ -4390,7 +4390,7 @@
MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
- bool is_getter,
+ AccessorComponent component,
Object* fun,
PropertyAttributes attributes) {
switch (GetElementsKind()) {
@@ -4412,7 +4412,7 @@
case DICTIONARY_ELEMENTS:
if (UpdateGetterSetterInDictionary(element_dictionary(),
index,
- is_getter,
+ component,
fun,
attributes)) {
return GetHeap()->undefined_value();
@@ -4433,7 +4433,7 @@
SeededNumberDictionary::cast(arguments);
if (UpdateGetterSetterInDictionary(dictionary,
index,
- is_getter,
+ component,
fun,
attributes)) {
return GetHeap()->undefined_value();
@@ -4448,14 +4448,14 @@
{ MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
if (!maybe_accessors->To(&accessors)) return maybe_accessors;
}
- accessors->set(is_getter, fun);
+ accessors->set(component, fun);
return SetElementCallback(index, accessors, attributes);
}
MaybeObject* JSObject::DefinePropertyAccessor(String* name,
- bool is_getter,
+ AccessorComponent component,
Object* fun,
PropertyAttributes attributes) {
// Lookup the name.
@@ -4473,7 +4473,7 @@
AccessorPair::cast(obj)->CopyWithoutTransitions();
if (!maybe_copy->To(©)) return maybe_copy;
}
- copy->set(is_getter, fun);
+ copy->set(component, fun);
// Use set to update attributes.
return SetPropertyCallback(name, copy, attributes);
}
@@ -4484,7 +4484,7 @@
{ MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
if (!maybe_accessors->To(&accessors)) return maybe_accessors;
}
- accessors->set(is_getter, fun);
+ accessors->set(component, fun);
return SetPropertyCallback(name, accessors, attributes);
}
@@ -4593,7 +4593,7 @@
}
MaybeObject* JSObject::DefineAccessor(String* name,
- bool is_getter,
+ AccessorComponent component,
Object* fun,
PropertyAttributes attributes) {
ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
@@ -4609,7 +4609,7 @@
Object* proto = GetPrototype();
if (proto->IsNull()) return this;
ASSERT(proto->IsJSGlobalObject());
- return JSObject::cast(proto)->DefineAccessor(name, is_getter,
+ return JSObject::cast(proto)->DefineAccessor(name, component,
fun, attributes);
}
@@ -4624,8 +4624,8 @@
uint32_t index = 0;
return name->AsArrayIndex(&index) ?
- DefineElementAccessor(index, is_getter, fun, attributes) :
- DefinePropertyAccessor(name, is_getter, fun, attributes);
+ DefineElementAccessor(index, component, fun, attributes) :
+ DefinePropertyAccessor(name, component, fun, attributes);
}
@@ -4711,7 +4711,7 @@
}
-Object* JSObject::LookupAccessor(String* name, bool is_getter) {
+Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
Heap* heap = GetHeap();
// Make sure that the top context does not change when doing callbacks or
@@ -4737,12 +4737,9 @@
int entry = dictionary->FindEntry(index);
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
- PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS) {
- if (element->IsAccessorPair()) {
- AccessorPair* accessors = AccessorPair::cast(element);
- return is_getter ? accessors->getter() : accessors->setter();
- }
+ if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
+ element->IsAccessorPair()) {
+ return AccessorPair::cast(element)->get(component);
}
}
}
@@ -4758,8 +4755,7 @@
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
if (obj->IsAccessorPair()) {
- AccessorPair* accessors = AccessorPair::cast(obj);
- return is_getter ? accessors->getter() : accessors->setter();
+ return AccessorPair::cast(obj)->get(component);
}
}
}
@@ -7880,9 +7876,7 @@
code()->set_optimizable(false);
}
if (FLAG_trace_opt) {
- PrintF("[disabled optimization for: ");
- DebugName()->ShortPrint();
- PrintF("]\n");
+ PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
}
}
@@ -8923,78 +8917,6 @@
}
-bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
- switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
- uint32_t length = IsJSArray() ?
- static_cast<uint32_t>
- (Smi::cast(JSArray::cast(this)->length())->value()) :
- static_cast<uint32_t>(FixedArray::cast(elements())->length());
- if ((index < length) &&
- !FixedArray::cast(elements())->get(index)->IsTheHole()) {
- return true;
- }
- break;
- }
- case FAST_DOUBLE_ELEMENTS: {
- uint32_t length = IsJSArray() ?
- static_cast<uint32_t>
- (Smi::cast(JSArray::cast(this)->length())->value()) :
- static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
- if ((index < length) &&
- !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
- return true;
- }
- break;
- }
- case EXTERNAL_PIXEL_ELEMENTS: {
- ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
- if (index < static_cast<uint32_t>(pixels->length())) {
- return true;
- }
- break;
- }
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS: {
- ExternalArray* array = ExternalArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- return true;
- }
- break;
- }
- case DICTIONARY_ELEMENTS: {
- if (element_dictionary()->FindEntry(index)
- != SeededNumberDictionary::kNotFound) {
- return true;
- }
- break;
- }
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
- }
-
- // Handle [] on String objects.
- if (this->IsStringObjectWithCharacterAt(index)) return true;
-
- Object* pt = GetPrototype();
- if (pt->IsNull()) return false;
- if (pt->IsJSProxy()) {
- // We need to follow the spec and simulate a call to [[GetOwnProperty]].
- return JSProxy::cast(pt)->GetElementAttributeWithHandler(
- receiver, index) != ABSENT;
- }
- return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
-}
-
-
bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Isolate* isolate = GetIsolate();
// Make sure that the top context does not change when doing
@@ -9034,7 +8956,21 @@
}
if (!result.IsEmpty()) return true;
}
- return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
+
+ if (holder_handle->GetElementsAccessor()->HasElement(
+ holder_handle->elements(), index, *holder_handle, *receiver_handle)) {
+ return true;
+ }
+
+ if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
+ Object* pt = holder_handle->GetPrototype();
+ if (pt->IsJSProxy()) {
+ // We need to follow the spec and simulate a call to [[GetOwnProperty]].
+ return JSProxy::cast(pt)->GetElementAttributeWithHandler(
+ receiver, index) != ABSENT;
+ }
+ if (pt->IsNull()) return false;
+ return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
}
@@ -9144,28 +9080,6 @@
}
-bool JSObject::HasElementInElements(FixedArray* elements,
- ElementsKind kind,
- uint32_t index) {
- ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
- if (kind == FAST_ELEMENTS) {
- int length = IsJSArray()
- ? Smi::cast(JSArray::cast(this)->length())->value()
- : elements->length();
- if (index < static_cast<uint32_t>(length) &&
- !elements->get(index)->IsTheHole()) {
- return true;
- }
- } else {
- if (SeededNumberDictionary::cast(elements)->FindEntry(index) !=
- SeededNumberDictionary::kNotFound) {
- return true;
- }
- }
- return false;
-}
-
-
bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
// Check access rights if needed.
if (IsAccessCheckNeeded()) {
@@ -9181,68 +9095,9 @@
return HasElementWithInterceptor(receiver, index);
}
- ElementsKind kind = GetElementsKind();
- switch (kind) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS: {
- uint32_t length = IsJSArray() ?
- static_cast<uint32_t>
- (Smi::cast(JSArray::cast(this)->length())->value()) :
- static_cast<uint32_t>(FixedArray::cast(elements())->length());
- if ((index < length) &&
- !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
- break;
- }
- case FAST_DOUBLE_ELEMENTS: {
- uint32_t length = IsJSArray() ?
- static_cast<uint32_t>
- (Smi::cast(JSArray::cast(this)->length())->value()) :
- static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
- if ((index < length) &&
- !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
- break;
- }
- case EXTERNAL_PIXEL_ELEMENTS: {
- ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
- if (index < static_cast<uint32_t>(pixels->length())) {
- return true;
- }
- break;
- }
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS: {
- ExternalArray* array = ExternalArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- return true;
- }
- break;
- }
- case DICTIONARY_ELEMENTS: {
- if (element_dictionary()->FindEntry(index)
- != SeededNumberDictionary::kNotFound) {
- return true;
- }
- break;
- }
- case NON_STRICT_ARGUMENTS_ELEMENTS: {
- FixedArray* parameter_map = FixedArray::cast(elements());
- uint32_t length = parameter_map->length();
- Object* probe =
- (index < length - 2) ? parameter_map->get(index + 2) : NULL;
- if (probe != NULL && !probe->IsTheHole()) return true;
-
- // Not a mapped parameter, check the arguments.
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
- if (HasElementInElements(arguments, kind, index)) return true;
- break;
- }
+ ElementsAccessor* accessor = GetElementsAccessor();
+ if (accessor->HasElement(elements(), index, this, receiver)) {
+ return true;
}
// Handle [] on String objects.
diff --git a/src/objects.h b/src/objects.h
index be75fab..3b0443c 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1360,6 +1360,13 @@
};
+// Indicator for one component of an AccessorPair.
+enum AccessorComponent {
+ ACCESSOR_GETTER,
+ ACCESSOR_SETTER
+};
+
+
// JSReceiver includes types on which properties can be defined, i.e.,
// JSObject and JSProxy.
class JSReceiver: public HeapObject {
@@ -1612,10 +1619,10 @@
bool continue_search);
MUST_USE_RESULT MaybeObject* DefineAccessor(String* name,
- bool is_getter,
+ AccessorComponent component,
Object* fun,
PropertyAttributes attributes);
- Object* LookupAccessor(String* name, bool is_getter);
+ Object* LookupAccessor(String* name, AccessorComponent component);
MUST_USE_RESULT MaybeObject* DefineAccessor(AccessorInfo* info);
@@ -1745,7 +1752,6 @@
LocalElementType HasLocalElement(uint32_t index);
bool HasElementWithInterceptor(JSReceiver* receiver, uint32_t index);
- bool HasElementPostInterceptor(JSReceiver* receiver, uint32_t index);
MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index,
Object* value,
@@ -2145,9 +2151,6 @@
bool ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
Object* object);
- bool HasElementInElements(FixedArray* elements,
- ElementsKind kind,
- uint32_t index);
// Returns true if most of the elements backing storage is used.
bool HasDenseElements();
@@ -2166,12 +2169,12 @@
PropertyAttributes attributes);
MUST_USE_RESULT MaybeObject* DefineElementAccessor(
uint32_t index,
- bool is_getter,
+ AccessorComponent component,
Object* fun,
PropertyAttributes attributes);
MUST_USE_RESULT MaybeObject* DefinePropertyAccessor(
String* name,
- bool is_getter,
+ AccessorComponent component,
Object* fun,
PropertyAttributes attributes);
void LookupInDescriptor(String* name, LookupResult* result);
@@ -2589,6 +2592,20 @@
static const int kMaxNumberOfDescriptors = 1024 + 512;
private:
+ // An entry in a DescriptorArray, represented as an (array, index) pair.
+ class Entry {
+ public:
+ inline explicit Entry(DescriptorArray* descs, int index) :
+ descs_(descs), index_(index) { }
+
+ inline PropertyType type() { return descs_->GetType(index_); }
+ inline Object* GetCallbackObject() { return descs_->GetValue(index_); }
+
+ private:
+ DescriptorArray* descs_;
+ int index_;
+ };
+
// Conversion from descriptor number to array indices.
static int ToKeyIndex(int descriptor_number) {
return descriptor_number+kFirstIndex;
@@ -4063,6 +4080,9 @@
// Casting.
static inline TypeFeedbackCells* cast(Object* obj);
+
+ static const int kForInFastCaseMarker = 0;
+ static const int kForInSlowCaseMarker = 1;
};
@@ -7910,15 +7930,24 @@
MUST_USE_RESULT MaybeObject* CopyWithoutTransitions();
- // TODO(svenpanne) Evil temporary helper, will vanish soon...
- void set(bool modify_getter, Object* value) {
- if (modify_getter) {
+ Object* get(AccessorComponent component) {
+ ASSERT(component == ACCESSOR_GETTER || component == ACCESSOR_SETTER);
+ return (component == ACCESSOR_GETTER) ? getter() : setter();
+ }
+
+ void set(AccessorComponent component, Object* value) {
+ ASSERT(component == ACCESSOR_GETTER || component == ACCESSOR_SETTER);
+ if (component == ACCESSOR_GETTER) {
set_getter(value);
} else {
set_setter(value);
}
}
+ bool ContainsAccessor() {
+ return IsJSAccessor(getter()) || IsJSAccessor(setter());
+ }
+
#ifdef OBJECT_PRINT
void AccessorPairPrint(FILE* out = stdout);
#endif
@@ -7931,6 +7960,15 @@
static const int kSize = kSetterOffset + kPointerSize;
private:
+ // Strangely enough, in addition to functions and harmony proxies, the spec
+ // requires us to consider undefined as a kind of accessor, too:
+ // var obj = {};
+ // Object.defineProperty(obj, "foo", {get: undefined});
+ // assertTrue("foo" in obj);
+ bool IsJSAccessor(Object* obj) {
+ return obj->IsSpecFunction() || obj->IsUndefined();
+ }
+
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorPair);
};
diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc
index 918327a..e05345c 100644
--- a/src/platform-nullos.cc
+++ b/src/platform-nullos.cc
@@ -55,6 +55,30 @@
}
+double fast_sin(double x) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+double fast_cos(double x) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+double fast_tan(double x) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+double fast_log(double x) {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
// Initialize OS class early in the V8 startup.
void OS::SetUp() {
// Seed the random number generator.
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 34fd5c4..4543a66 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -53,6 +53,7 @@
#include "v8.h"
+#include "codegen.h"
#include "platform.h"
namespace v8 {
@@ -126,6 +127,29 @@
}
+static Mutex* transcendental_function_mutex = OS::CreateMutex();
+
+#define TRANSCENDENTAL_FUNCTION(name, type) \
+static TranscendentalFunction fast_##name##_function = NULL; \
+double fast_##name(double x) { \
+ if (fast_##name##_function == NULL) { \
+ ScopedLock lock(transcendental_function_mutex); \
+ TranscendentalFunction temp = \
+ CreateTranscendentalFunction(type); \
+ MemoryBarrier(); \
+ fast_##name##_function = temp; \
+ } \
+ return (*fast_##name##_function)(x); \
+}
+
+TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN)
+TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS)
+TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN)
+TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG)
+
+#undef TRANSCENDENTAL_FUNCTION
+
+
double OS::nan_value() {
// NAN from math.h is defined in C99 and not in POSIX.
return NAN;
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index e9e9924..53915c6 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -32,6 +32,7 @@
#include "v8.h"
+#include "codegen.h"
#include "platform.h"
#include "vm-state-inl.h"
@@ -112,11 +113,16 @@
}
+#ifndef __MINGW64_VERSION_MAJOR
+
inline void MemoryBarrier() {
int barrier = 0;
__asm__ __volatile__("xchgl %%eax,%0 ":"=r" (barrier));
}
+#endif // __MINGW64_VERSION_MAJOR
+
+
#endif // __MINGW32__
// Generate a pseudo-random number in the range 0-2^31-1. Usually
@@ -201,6 +207,30 @@
#endif // _WIN64
+
+static Mutex* transcendental_function_mutex = OS::CreateMutex();
+
+#define TRANSCENDENTAL_FUNCTION(name, type) \
+static TranscendentalFunction fast_##name##_function = NULL; \
+double fast_##name(double x) { \
+ if (fast_##name##_function == NULL) { \
+ ScopedLock lock(transcendental_function_mutex); \
+ TranscendentalFunction temp = \
+ CreateTranscendentalFunction(type); \
+ MemoryBarrier(); \
+ fast_##name##_function = temp; \
+ } \
+ return (*fast_##name##_function)(x); \
+}
+
+TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN)
+TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS)
+TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN)
+TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG)
+
+#undef TRANSCENDENTAL_FUNCTION
+
+
// ----------------------------------------------------------------------------
// The Time class represents time on win32. A timestamp is represented as
// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
@@ -885,7 +915,6 @@
bool is_executable) {
// VirtualAlloc rounds allocated size to page size automatically.
size_t msize = RoundUp(requested, static_cast<int>(GetPageSize()));
- void* address = 0;
// Windows XP SP2 allows Data Excution Prevention (DEP).
int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
@@ -938,12 +967,8 @@
void OS::Abort() {
if (!IsDebuggerPresent()) {
-#ifdef _MSC_VER
// Make the MSVCRT do a silent abort.
- _set_abort_behavior(0, _WRITE_ABORT_MSG);
- _set_abort_behavior(0, _CALL_REPORTFAULT);
-#endif // _MSC_VER
- abort();
+ raise(SIGABRT);
} else {
DebugBreak();
}
diff --git a/src/platform.h b/src/platform.h
index 38e633a..ccb4109 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -96,6 +96,12 @@
double ceiling(double x);
double modulo(double x, double y);
+// Custom implementation of sin, cos, tan and log.
+double fast_sin(double input);
+double fast_cos(double input);
+double fast_tan(double input);
+double fast_log(double input);
+
// Forward declarations.
class Socket;
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index dd2f701..14349cc 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -992,8 +992,8 @@
const char* name,
HeapEntry* entry,
int retainer_index) {
- children_arr()[child_index].Init(child_index, type, name, entry);
- entry->retainers_arr()[retainer_index] = children_arr() + child_index;
+ children()[child_index].Init(child_index, type, name, entry);
+ entry->retainers()[retainer_index] = children_arr() + child_index;
}
@@ -1002,14 +1002,14 @@
int index,
HeapEntry* entry,
int retainer_index) {
- children_arr()[child_index].Init(child_index, type, index, entry);
- entry->retainers_arr()[retainer_index] = children_arr() + child_index;
+ children()[child_index].Init(child_index, type, index, entry);
+ entry->retainers()[retainer_index] = children_arr() + child_index;
}
void HeapEntry::SetUnidirElementReference(
int child_index, int index, HeapEntry* entry) {
- children_arr()[child_index].Init(child_index, index, entry);
+ children()[child_index].Init(child_index, index, entry);
}
@@ -1671,18 +1671,6 @@
GetGcSubrootOrder(object),
children_count,
retainers_count);
- } else if (object->IsJSGlobalObject()) {
- const char* tag = objects_tags_.GetTag(object);
- const char* name = collection_->names()->GetName(
- GetConstructorName(JSObject::cast(object)));
- if (tag != NULL) {
- name = collection_->names()->GetFormatted("%s / %s", name, tag);
- }
- return AddEntry(object,
- HeapEntry::kObject,
- name,
- children_count,
- retainers_count);
} else if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
@@ -1703,8 +1691,7 @@
} else if (object->IsJSObject()) {
return AddEntry(object,
HeapEntry::kObject,
- collection_->names()->GetName(
- GetConstructorName(JSObject::cast(object))),
+ "",
children_count,
retainers_count);
} else if (object->IsString()) {
@@ -2349,6 +2336,32 @@
}
+bool V8HeapExplorer::IterateAndSetObjectNames(SnapshotFillerInterface* filler) {
+ HeapIterator iterator(HeapIterator::kFilterUnreachable);
+ filler_ = filler;
+ for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
+ SetObjectName(obj);
+ }
+ return true;
+}
+
+
+void V8HeapExplorer::SetObjectName(HeapObject* object) {
+ if (!object->IsJSObject() || object->IsJSRegExp() || object->IsJSFunction()) {
+ return;
+ }
+ const char* name = collection_->names()->GetName(
+ GetConstructorName(JSObject::cast(object)));
+ if (object->IsJSGlobalObject()) {
+ const char* tag = objects_tags_.GetTag(object);
+ if (tag != NULL) {
+ name = collection_->names()->GetFormatted("%s / %s", name, tag);
+ }
+ }
+ GetEntry(object)->set_name(name);
+}
+
+
void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
String* reference_name,
@@ -2907,15 +2920,6 @@
}
-HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot,
- v8::ActivityControl* control)
- : snapshot_(snapshot),
- control_(control),
- v8_heap_explorer_(snapshot_, this),
- dom_explorer_(snapshot_, this) {
-}
-
-
class SnapshotCounter : public SnapshotFillerInterface {
public:
explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { }
@@ -3040,6 +3044,15 @@
};
+HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot,
+ v8::ActivityControl* control)
+ : snapshot_(snapshot),
+ control_(control),
+ v8_heap_explorer_(snapshot_, this),
+ dom_explorer_(snapshot_, this) {
+}
+
+
bool HeapSnapshotGenerator::GenerateSnapshot() {
v8_heap_explorer_.TagGlobalObjects();
@@ -3084,10 +3097,12 @@
debug_heap->Verify();
#endif
- // Allocate and fill entries in the snapshot, allocate references.
+ // Allocate memory for entries and references.
snapshot_->AllocateEntries(entries_.entries_count(),
entries_.total_children_count(),
entries_.total_retainers_count());
+
+ // Allocate heap objects to entries hash map.
entries_.AllocateEntries();
// Pass 2. Fill references.
@@ -3132,17 +3147,22 @@
bool HeapSnapshotGenerator::CountEntriesAndReferences() {
SnapshotCounter counter(&entries_);
v8_heap_explorer_.AddRootEntries(&counter);
- return
- v8_heap_explorer_.IterateAndExtractReferences(&counter) &&
- dom_explorer_.IterateAndExtractReferences(&counter);
+ return v8_heap_explorer_.IterateAndExtractReferences(&counter)
+ && dom_explorer_.IterateAndExtractReferences(&counter);
}
bool HeapSnapshotGenerator::FillReferences() {
SnapshotFiller filler(snapshot_, &entries_);
- return
- v8_heap_explorer_.IterateAndExtractReferences(&filler) &&
- dom_explorer_.IterateAndExtractReferences(&filler);
+ // IterateAndExtractReferences cannot set object names because
+ // it makes call to JSObject::LocalLookupRealNamedProperty which
+ // in turn may relocate objects in property maps thus changing the heap
+ // layout and affecting retainer counts. This is not acceptable because
+ // number of retainers must not change between count and fill passes.
+ // To avoid this there's a separate postpass that set object names.
+ return v8_heap_explorer_.IterateAndExtractReferences(&filler)
+ && dom_explorer_.IterateAndExtractReferences(&filler)
+ && v8_heap_explorer_.IterateAndSetObjectNames(&filler);
}
@@ -3198,26 +3218,28 @@
for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator;
(*dominators)[root_index] = root_index;
- // The painted flag is used to mark entries that need to be recalculated
- // because of dominators change among their retainers.
- for (int i = 0; i < entries_length; ++i) entries[i]->clear_paint();
-
+ // The affected array is used to mark entries which dominators
+ // have to be racalculated because of changes in their retainers.
+ ScopedVector<bool> affected(entries_length);
+ for (int i = 0; i < affected.length(); ++i) affected[i] = false;
// Mark the root direct children as affected.
Vector<HeapGraphEdge> children = entries[root_index]->children();
- for (int i = 0; i < children.length(); ++i) children[i].to()->paint();
+ for (int i = 0; i < children.length(); ++i) {
+ affected[children[i].to()->ordered_index()] = true;
+ }
bool changed = true;
while (changed) {
changed = false;
+ if (!ProgressReport(true)) return false;
for (int i = root_index - 1; i >= 0; --i) {
+ if (!affected[i]) continue;
+ affected[i] = false;
// If dominator of the entry has already been set to root,
// then it can't propagate any further.
if ((*dominators)[i] == root_index) continue;
- HeapEntry* entry = entries[i];
- if (!entry->painted()) continue;
- entry->clear_paint();
int new_idom_index = kNoDominator;
- Vector<HeapGraphEdge*> rets = entry->retainers();
+ Vector<HeapGraphEdge*> rets = entries[i]->retainers();
for (int j = 0; j < rets.length(); ++j) {
if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
int ret_index = rets[j]->From()->ordered_index();
@@ -3235,7 +3257,9 @@
(*dominators)[i] = new_idom_index;
changed = true;
Vector<HeapGraphEdge> children = entries[i]->children();
- for (int j = 0; j < children.length(); ++j) children[j].to()->paint();
+ for (int j = 0; j < children.length(); ++j) {
+ affected[children[j].to()->ordered_index()] = true;
+ }
}
}
}
@@ -3490,6 +3514,9 @@
|| edge->type() == HeapGraphEdge::kHidden
|| edge->type() == HeapGraphEdge::kWeak
? edge->index() : GetStringId(edge->name());
+ STATIC_CHECK(sizeof(int) == sizeof(edge->type())); // NOLINT
+ STATIC_CHECK(sizeof(int) == sizeof(edge_name_or_index)); // NOLINT
+ STATIC_CHECK(sizeof(int) == sizeof(GetNodeId(edge->to()))); // NOLINT
int result = OS::SNPrintF(buffer, ",%d,%d,%d",
edge->type(), edge_name_or_index, GetNodeId(edge->to()));
USE(result);
@@ -3499,12 +3526,21 @@
void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
- // The buffer needs space for 7 ints, 7 commas, \n and \0
+ // The buffer needs space for 6 ints, 1 uint64_t, 7 commas, \n and \0
static const int kBufferSize =
- MaxDecimalDigitsIn<sizeof(int)>::kSigned * 7 + 7 + 1 + 1; // NOLINT
+ 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT
+ + MaxDecimalDigitsIn<sizeof(uint64_t)>::kUnsigned // NOLINT
+ + 7 + 1 + 1;
EmbeddedVector<char, kBufferSize> buffer;
Vector<HeapGraphEdge> children = entry->children();
- int result = OS::SNPrintF(buffer, "\n,%d,%d,%d,%d,%d,%d,%d",
+ STATIC_CHECK(sizeof(int) == sizeof(entry->type())); // NOLINT
+ STATIC_CHECK(sizeof(int) == sizeof(GetStringId(entry->name()))); // NOLINT
+ STATIC_CHECK(sizeof(uint64_t) == sizeof(entry->id())); // NOLINT
+ STATIC_CHECK(sizeof(int) == sizeof(entry->self_size())); // NOLINT
+ STATIC_CHECK(sizeof(int) == sizeof(entry->retained_size())); // NOLINT
+ STATIC_CHECK(sizeof(int) == sizeof(GetNodeId(entry->dominator()))); // NOLINT
+ STATIC_CHECK(sizeof(int) == sizeof(children.length())); // NOLINT
+ int result = OS::SNPrintF(buffer, "\n,%d,%d,%llu,%d,%d,%d,%d",
entry->type(),
GetStringId(entry->name()),
entry->id(),
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 22a0473..f9ae5f9 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -541,6 +541,7 @@
HeapSnapshot* snapshot() { return snapshot_; }
Type type() { return static_cast<Type>(type_); }
const char* name() { return name_; }
+ void set_name(const char* name) { name_ = name; }
inline uint64_t id();
int self_size() { return self_size_; }
int retained_size() { return retained_size_; }
@@ -918,6 +919,7 @@
void AddRootEntries(SnapshotFillerInterface* filler);
int EstimateObjectsCount(HeapIterator* iterator);
bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
+ bool IterateAndSetObjectNames(SnapshotFillerInterface* filler);
void TagGlobalObjects();
static String* GetConstructorName(JSObject* object);
@@ -984,6 +986,7 @@
void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
void SetGcSubrootReference(
VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
+ void SetObjectName(HeapObject* object);
void TagObject(Object* obj, const char* tag);
HeapEntry* GetEntry(Object* obj);
diff --git a/src/property-details.h b/src/property-details.h
index 81f521a..c79aa96 100644
--- a/src/property-details.h
+++ b/src/property-details.h
@@ -73,26 +73,6 @@
};
-inline bool IsRealProperty(PropertyType type) {
- switch (type) {
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case CALLBACKS:
- case HANDLER:
- case INTERCEPTOR:
- return true;
- case MAP_TRANSITION:
- case ELEMENTS_TRANSITION:
- case CONSTANT_TRANSITION:
- case NULL_DESCRIPTOR:
- return false;
- }
- UNREACHABLE(); // keep the compiler happy
- return false;
-}
-
-
// PropertyDetails captures type and attributes for a property.
// They are used both in property dictionaries and instance descriptors.
class PropertyDetails BASE_EMBEDDED {
diff --git a/src/property.h b/src/property.h
index d5efb7f..9235c32 100644
--- a/src/property.h
+++ b/src/property.h
@@ -164,6 +164,35 @@
};
+template <class T>
+bool IsPropertyDescriptor(T* desc) {
+ switch (desc->type()) {
+ case NORMAL:
+ case FIELD:
+ case CONSTANT_FUNCTION:
+ case HANDLER:
+ case INTERCEPTOR:
+ return true;
+ case CALLBACKS: {
+ Object* callback_object = desc->GetCallbackObject();
+ // Non-JavaScript (i.e. native) accessors are always a property, otherwise
+ // either the getter or the setter must be an accessor. Put another way:
+ // If we only see map transitions and holes in a pair, this is not a
+ // property.
+ return (!callback_object->IsAccessorPair() ||
+ AccessorPair::cast(callback_object)->ContainsAccessor());
+ }
+ case MAP_TRANSITION:
+ case ELEMENTS_TRANSITION:
+ case CONSTANT_TRANSITION:
+ case NULL_DESCRIPTOR:
+ return false;
+ }
+ UNREACHABLE(); // keep the compiler happy
+ return false;
+}
+
+
class LookupResult BASE_EMBEDDED {
public:
explicit LookupResult(Isolate* isolate)
@@ -261,10 +290,9 @@
bool IsFound() { return lookup_type_ != NOT_FOUND; }
bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
- // Is the result is a property excluding transitions and the null
- // descriptor?
+ // Is the result is a property excluding transitions and the null descriptor?
bool IsProperty() {
- return IsFound() && IsRealProperty(GetPropertyDetails().type());
+ return IsFound() && IsPropertyDescriptor(this);
}
bool IsCacheable() { return cacheable_; }
diff --git a/src/runtime.cc b/src/runtime.cc
index d9c5bed..34a47c5 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -4318,7 +4318,7 @@
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
- CONVERT_SMI_ARG_CHECKED(flag_setter, 2);
+ CONVERT_SMI_ARG_CHECKED(flag, 2);
Object* fun = args[3];
CONVERT_SMI_ARG_CHECKED(unchecked, 4);
@@ -4327,7 +4327,8 @@
RUNTIME_ASSERT(!obj->IsNull());
RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
- return obj->DefineAccessor(name, flag_setter == 0, fun, attr);
+ AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
+ return obj->DefineAccessor(name, component, fun, attr);
}
// Implements part of 8.12.9 DefineOwnProperty.
@@ -10292,7 +10293,8 @@
CONVERT_ARG_CHECKED(JSObject, obj, 0);
CONVERT_ARG_CHECKED(String, name, 1);
CONVERT_SMI_ARG_CHECKED(flag, 2);
- return obj->LookupAccessor(name, flag == 0);
+ AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
+ return obj->LookupAccessor(name, component);
}
diff --git a/src/spaces.h b/src/spaces.h
index 599e9dd..75ca534 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -506,6 +506,11 @@
size_ = size;
}
+ void SetArea(Address area_start, Address area_end) {
+ area_start_ = area_start;
+ area_end_ = area_end;
+ }
+
Executability executable() {
return IsFlagSet(IS_EXECUTABLE) ? EXECUTABLE : NOT_EXECUTABLE;
}
diff --git a/src/strtod.cc b/src/strtod.cc
index be79c80..0dc618a 100644
--- a/src/strtod.cc
+++ b/src/strtod.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -175,13 +175,15 @@
static bool DoubleStrtod(Vector<const char> trimmed,
int exponent,
double* result) {
-#if (defined(V8_TARGET_ARCH_IA32) || defined(USE_SIMULATOR)) && !defined(WIN32)
+#if (defined(V8_TARGET_ARCH_IA32) || defined(USE_SIMULATOR)) \
+ && !defined(_MSC_VER)
// On x86 the floating-point stack can be 64 or 80 bits wide. If it is
// 80 bits wide (as is the case on Linux) then double-rounding occurs and the
// result is not accurate.
- // We know that Windows32 uses 64 bits and is therefore accurate.
- // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
- // the same problem.
+ // We know that Windows32 with MSVC, unlike with MinGW32, uses 64 bits and is
+ // therefore accurate.
+ // Note that the ARM and MIPS simulators are compiled for 32bits. They
+ // therefore exhibit the same problem.
return false;
#endif
if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
diff --git a/src/token.h b/src/token.h
index 1eeb60d..3036e55 100644
--- a/src/token.h
+++ b/src/token.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -215,7 +215,7 @@
return EQ <= op && op <= IN;
}
- static bool IsOrderedCompareOp(Value op) {
+ static bool IsOrderedRelationalCompareOp(Value op) {
return op == LT || op == LTE || op == GT || op == GTE;
}
diff --git a/src/type-info.cc b/src/type-info.cc
index 81cbff3..fa479b2 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -154,6 +154,13 @@
}
+bool TypeFeedbackOracle::IsForInFastCase(ForInStatement* stmt) {
+ Handle<Object> value = GetInfo(stmt->PrepareId());
+ return value->IsSmi() &&
+ Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker;
+}
+
+
Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) {
ASSERT(LoadIsMonomorphicNormal(expr));
Handle<Object> map_or_code = GetInfo(expr->id());
@@ -659,9 +666,10 @@
for (int i = 0; i < cache->CellCount(); i++) {
unsigned ast_id = cache->AstId(i)->value();
Object* value = cache->Cell(i)->value();
- if (value->IsJSFunction() &&
- !CanRetainOtherContext(JSFunction::cast(value),
- *global_context_)) {
+ if (value->IsSmi() ||
+ (value->IsJSFunction() &&
+ !CanRetainOtherContext(JSFunction::cast(value),
+ *global_context_))) {
SetInfo(ast_id, value);
}
}
diff --git a/src/type-info.h b/src/type-info.h
index 19a309b..84ec51d 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -228,6 +228,7 @@
class Property;
class SmallMapList;
class UnaryOperation;
+class ForInStatement;
class TypeFeedbackOracle BASE_EMBEDDED {
@@ -243,6 +244,8 @@
bool CallIsMonomorphic(Call* expr);
bool CallNewIsMonomorphic(CallNew* expr);
+ bool IsForInFastCase(ForInStatement* expr);
+
Handle<Map> LoadMonomorphicReceiverType(Property* expr);
Handle<Map> StoreMonomorphicReceiverType(Expression* expr);
diff --git a/src/v8natives.js b/src/v8natives.js
index 381d341..8906f9e 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -332,7 +332,7 @@
function ObjectKeys(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
+ throw MakeTypeError("called_on_non_object", ["Object.keys"]);
}
if (%IsJSProxy(obj)) {
var handler = %GetHandler(obj);
@@ -943,7 +943,7 @@
// ES5 section 15.2.3.2.
function ObjectGetPrototypeOf(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
+ throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
}
return %GetPrototype(obj);
}
@@ -952,8 +952,8 @@
// ES5 section 15.2.3.3
function ObjectGetOwnPropertyDescriptor(obj, p) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object",
- ["getOwnPropertyDescriptor"]);
+ throw MakeTypeError("called_on_non_object",
+ ["Object.getOwnPropertyDescriptor"]);
}
var desc = GetOwnProperty(obj, p);
return FromPropertyDescriptor(desc);
@@ -983,8 +983,7 @@
// ES5 section 15.2.3.4.
function ObjectGetOwnPropertyNames(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object",
- ["getOwnPropertyNames"]);
+ throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
}
// Special handling for proxies.
if (%IsJSProxy(obj)) {
@@ -1057,7 +1056,7 @@
// ES5 section 15.2.3.6.
function ObjectDefineProperty(obj, p, attributes) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
+ throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
}
var name = ToString(p);
if (%IsJSProxy(obj)) {
@@ -1109,7 +1108,7 @@
// ES5 section 15.2.3.7.
function ObjectDefineProperties(obj, properties) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
+ throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
}
var props = ToObject(properties);
var names = GetOwnEnumerablePropertyNames(props);
@@ -1156,7 +1155,7 @@
// ES5 section 15.2.3.8.
function ObjectSeal(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
+ throw MakeTypeError("called_on_non_object", ["Object.seal"]);
}
if (%IsJSProxy(obj)) {
ProxyFix(obj);
@@ -1178,7 +1177,7 @@
// ES5 section 15.2.3.9.
function ObjectFreeze(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
+ throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
}
if (%IsJSProxy(obj)) {
ProxyFix(obj);
@@ -1201,7 +1200,7 @@
// ES5 section 15.2.3.10
function ObjectPreventExtension(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
+ throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
}
if (%IsJSProxy(obj)) {
ProxyFix(obj);
@@ -1214,7 +1213,7 @@
// ES5 section 15.2.3.11
function ObjectIsSealed(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
+ throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
}
if (%IsJSProxy(obj)) {
return false;
@@ -1235,7 +1234,7 @@
// ES5 section 15.2.3.12
function ObjectIsFrozen(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
+ throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
}
if (%IsJSProxy(obj)) {
return false;
@@ -1257,7 +1256,7 @@
// ES5 section 15.2.3.13
function ObjectIsExtensible(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
+ throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
}
if (%IsJSProxy(obj)) {
return true;
diff --git a/src/version.cc b/src/version.cc
index a7445f1..8d877a3 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 9
-#define BUILD_NUMBER 14
+#define BUILD_NUMBER 15
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/win32-headers.h b/src/win32-headers.h
index 87f078d..5d9c89e 100644
--- a/src/win32-headers.h
+++ b/src/win32-headers.h
@@ -56,6 +56,7 @@
#include <windows.h>
#ifdef V8_WIN32_HEADERS_FULL
+#include <signal.h> // For raise().
#include <time.h> // For LocalOffset() implementation.
#include <mmsystem.h> // For timeGetTime().
#ifdef __MINGW32__
@@ -78,7 +79,7 @@
#ifndef __MINGW32__
#include <wspiapi.h>
#endif // __MINGW32__
-#include <process.h> // for _beginthreadex()
+#include <process.h> // For _beginthreadex().
#include <stdlib.h>
#endif // V8_WIN32_HEADERS_FULL
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 5587609..2bfb004 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -1628,7 +1628,7 @@
__ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
__ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
}
- GenerateOperation(masm);
+ GenerateOperation(masm, type_);
__ movq(Operand(rcx, 0), rbx);
__ movq(Operand(rcx, 2 * kIntSize), rax);
__ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
@@ -1643,7 +1643,7 @@
__ subq(rsp, Immediate(kDoubleSize));
__ movsd(Operand(rsp, 0), xmm1);
__ fld_d(Operand(rsp, 0));
- GenerateOperation(masm);
+ GenerateOperation(masm, type_);
__ fstp_d(Operand(rsp, 0));
__ movsd(xmm1, Operand(rsp, 0));
__ addq(rsp, Immediate(kDoubleSize));
@@ -1695,16 +1695,17 @@
}
-void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
+void TranscendentalCacheStub::GenerateOperation(
+ MacroAssembler* masm, TranscendentalCache::Type type) {
// Registers:
// rax: Newly allocated HeapNumber, which must be preserved.
// rbx: Bits of input double. Must be preserved.
// rcx: Pointer to cache entry. Must be preserved.
// st(0): Input double
Label done;
- if (type_ == TranscendentalCache::SIN ||
- type_ == TranscendentalCache::COS ||
- type_ == TranscendentalCache::TAN) {
+ if (type == TranscendentalCache::SIN ||
+ type == TranscendentalCache::COS ||
+ type == TranscendentalCache::TAN) {
// Both fsin and fcos require arguments in the range +/-2^63 and
// return NaN for infinities and NaN. They can share all code except
// the actual fsin/fcos operation.
@@ -1725,8 +1726,12 @@
__ j(not_equal, &non_nan_result, Label::kNear);
// Input is +/-Infinity or NaN. Result is NaN.
__ fstp(0);
- __ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex);
- __ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
+ // NaN is represented by 0x7ff8000000000000.
+ __ subq(rsp, Immediate(kPointerSize));
+ __ movl(Operand(rsp, 4), Immediate(0x7ff80000));
+ __ movl(Operand(rsp, 0), Immediate(0x00000000));
+ __ fld_d(Operand(rsp, 0));
+ __ addq(rsp, Immediate(kPointerSize));
__ jmp(&done);
__ bind(&non_nan_result);
@@ -1767,7 +1772,7 @@
// FPU Stack: input % 2*pi
__ movq(rax, rdi); // Restore rax, pointer to the new HeapNumber.
__ bind(&in_range);
- switch (type_) {
+ switch (type) {
case TranscendentalCache::SIN:
__ fsin();
break;
@@ -1785,7 +1790,7 @@
}
__ bind(&done);
} else {
- ASSERT(type_ == TranscendentalCache::LOG);
+ ASSERT(type == TranscendentalCache::LOG);
__ fldln2();
__ fxch();
__ fyl2x();
@@ -5522,15 +5527,15 @@
ASSERT(state_ == CompareIC::HEAP_NUMBERS);
Label generic_stub;
- Label unordered;
+ Label unordered, maybe_undefined1, maybe_undefined2;
Label miss;
Condition either_smi = masm->CheckEitherSmi(rax, rdx);
__ j(either_smi, &generic_stub, Label::kNear);
__ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx);
- __ j(not_equal, &miss, Label::kNear);
+ __ j(not_equal, &maybe_undefined1, Label::kNear);
__ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
- __ j(not_equal, &miss, Label::kNear);
+ __ j(not_equal, &maybe_undefined2, Label::kNear);
// Load left and right operand
__ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
@@ -5551,11 +5556,25 @@
__ ret(0);
__ bind(&unordered);
-
CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
__ bind(&generic_stub);
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+ __ bind(&maybe_undefined1);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ Cmp(rax, masm->isolate()->factory()->undefined_value());
+ __ j(not_equal, &miss);
+ __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
+ __ j(not_equal, &maybe_undefined2, Label::kNear);
+ __ jmp(&unordered);
+ }
+
+ __ bind(&maybe_undefined2);
+ if (Token::IsOrderedRelationalCompareOp(op_)) {
+ __ Cmp(rdx, masm->isolate()->factory()->undefined_value());
+ __ j(equal, &unordered);
+ }
+
__ bind(&miss);
GenerateMiss(masm);
}
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index 30ef3e8..6a1a18f 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -48,6 +48,8 @@
ArgumentType argument_type)
: type_(type), argument_type_(argument_type) {}
void Generate(MacroAssembler* masm);
+ static void GenerateOperation(MacroAssembler* masm,
+ TranscendentalCache::Type type);
private:
TranscendentalCache::Type type_;
ArgumentType argument_type_;
@@ -55,7 +57,6 @@
Major MajorKey() { return TranscendentalCache; }
int MinorKey() { return type_ | argument_type_; }
Runtime::FunctionId RuntimeFunction();
- void GenerateOperation(MacroAssembler* masm);
};
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 8947f70..2584889 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -54,6 +54,52 @@
#define __ masm.
+
+TranscendentalFunction CreateTranscendentalFunction(
+ TranscendentalCache::Type type) {
+ size_t actual_size;
+ // Allocate buffer in executable space.
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
+ &actual_size,
+ true));
+ if (buffer == NULL) {
+ // Fallback to library function if function cannot be created.
+ switch (type) {
+ case TranscendentalCache::SIN: return &sin;
+ case TranscendentalCache::COS: return &cos;
+ case TranscendentalCache::TAN: return &tan;
+ case TranscendentalCache::LOG: return &log;
+ default: UNIMPLEMENTED();
+ }
+ }
+
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+ // xmm0: raw double input.
+ // Move double input into registers.
+ __ push(rbx);
+ __ push(rdi);
+ __ movq(rbx, xmm0);
+ __ push(rbx);
+ __ fld_d(Operand(rsp, 0));
+ TranscendentalCacheStub::GenerateOperation(&masm, type);
+ // The return value is expected to be in xmm0.
+ __ fstp_d(Operand(rsp, 0));
+ __ pop(rbx);
+ __ movq(xmm0, rbx);
+ __ pop(rdi);
+ __ pop(rbx);
+ __ Ret();
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+ ASSERT(desc.reloc_size == 0);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+ return FUNCTION_CAST<TranscendentalFunction>(buffer);
+}
+
+
#ifdef _WIN64
typedef double (*ModuloFunction)(double, double);
// Define custom fmod implementation.
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index a9bf9a8..7a60adc 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -969,6 +969,16 @@
// We got a fixed array in register rax. Iterate through that.
Label non_proxy;
__ bind(&fixed_array);
+
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(
+ Handle<Object>(
+ Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
+ RecordTypeFeedbackCell(stmt->PrepareId(), cell);
+ __ LoadHeapObject(rbx, cell);
+ __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
+ Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker));
+
__ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
__ movq(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 8615a4d..985cdc6 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -67,7 +67,7 @@
#define __ masm()->
bool LCodeGen::GenerateCode() {
- HPhase phase("Z Code generation", chunk());
+ HPhase phase("Z_Code generation", chunk());
ASSERT(is_unused());
status_ = GENERATING;
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 8cddb36..79ca5f5 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -382,7 +382,7 @@
void LChunk::MarkEmptyBlocks() {
- HPhase phase("L Mark empty blocks", this);
+ HPhase phase("L_Mark empty blocks", this);
for (int i = 0; i < graph()->blocks()->length(); ++i) {
HBasicBlock* block = graph()->blocks()->at(i);
int first = block->first_instruction_index();
@@ -545,7 +545,7 @@
LChunk* LChunkBuilder::Build() {
ASSERT(is_unused());
chunk_ = new(zone()) LChunk(info(), graph());
- HPhase phase("L Building chunk", chunk_);
+ HPhase phase("L_Building chunk", chunk_);
status_ = BUILDING;
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
for (int i = 0; i < blocks->length(); i++) {
@@ -1163,7 +1163,7 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
- if (op == kMathLog || op == kMathSin || op == kMathCos) {
+ if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* input = UseFixedDouble(instr->value(), xmm1);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index 773fc4c..70c72d4 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -318,7 +318,7 @@
void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
Label fallthrough;
__ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
- __ j(not_equal, &fallthrough);
+ __ j(not_equal, &fallthrough, Label::kNear);
Drop();
BranchOrBacktrack(no_condition, on_equal);
__ bind(&fallthrough);
@@ -368,7 +368,7 @@
// al - input character
// dl - capture character
__ cmpb(rax, rdx);
- __ j(equal, &loop_increment);
+ __ j(equal, &loop_increment, Label::kNear);
// Mismatch, try case-insensitive match (converting letters to lower-case).
// I.e., if or-ing with 0x20 makes values equal and in range 'a'-'z', it's
@@ -585,7 +585,7 @@
// ASCII space characters are '\t'..'\r' and ' '.
Label success;
__ cmpl(current_character(), Immediate(' '));
- __ j(equal, &success);
+ __ j(equal, &success, Label::kNear);
// Check range 0x09..0x0d
__ lea(rax, Operand(current_character(), -'\t'));
__ cmpl(rax, Immediate('\r' - '\t'));
@@ -676,7 +676,7 @@
if (mode_ != ASCII) {
// Table is 128 entries, so all ASCII characters can be tested.
__ cmpl(current_character(), Immediate('z'));
- __ j(above, &done);
+ __ j(above, &done, Label::kNear);
}
__ movq(rbx, ExternalReference::re_word_character_map());
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
@@ -763,11 +763,11 @@
__ movq(kScratchRegister, stack_limit);
__ subq(rcx, Operand(kScratchRegister, 0));
// Handle it if the stack pointer is already below the stack limit.
- __ j(below_equal, &stack_limit_hit);
+ __ j(below_equal, &stack_limit_hit, Label::kNear);
// Check if there is room for the variable number of registers above
// the stack limit.
__ cmpq(rcx, Immediate(num_registers_ * kPointerSize));
- __ j(above_equal, &stack_ok);
+ __ j(above_equal, &stack_ok, Label::kNear);
// Exit with OutOfMemory exception. There is not enough space on the stack
// for our working registers.
__ Set(rax, EXCEPTION);
@@ -833,7 +833,7 @@
// Load previous char as initial value of current-character.
Label at_start;
__ cmpb(Operand(rbp, kStartIndex), Immediate(0));
- __ j(equal, &at_start);
+ __ j(equal, &at_start, Label::kNear);
LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
__ jmp(&start_label_);
__ bind(&at_start);
@@ -1370,7 +1370,7 @@
ExternalReference::address_of_stack_limit(masm_.isolate());
__ load_rax(stack_limit);
__ cmpq(rsp, rax);
- __ j(above, &no_preempt);
+ __ j(above, &no_preempt, Label::kNear);
SafeCall(&check_preempt_label_);
@@ -1384,7 +1384,7 @@
ExternalReference::address_of_regexp_stack_limit(masm_.isolate());
__ load_rax(stack_limit);
__ cmpq(backtrack_stackpointer(), rax);
- __ j(above, &no_stack_overflow);
+ __ j(above, &no_stack_overflow, Label::kNear);
SafeCall(&stack_overflow_label_);