Version 3.15.3
Changed sample shell to send non-JS output (e.g. errors) to stderr instead of stdout.
Correctly check for stack overflow even when interrupt is pending. (issue 214)
Collect stack trace on stack overflow. (issue 2394)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@12947 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index bb9ed30..900aea9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2012-11-13: Version 3.15.3
+
+ Changed sample shell to send non-JS output (e.g. errors) to stderr
+ instead of stdout.
+
+ Correctly check for stack overflow even when interrupt is pending.
+ (issue 214)
+
+ Collect stack trace on stack overflow. (issue 2394)
+
+ Performance and stability improvements on all platforms.
+
+
2012-11-12: Version 3.15.2
Function::GetScriptOrigin supplies sourceURL when script name is
diff --git a/include/v8.h b/include/v8.h
index cf9275d..28bea2e 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -76,6 +76,17 @@
#endif // _WIN32
+// TODO(svenpanne) Remove this when the Chrome's v8 bindings have been adapted.
+#define V8_DISABLE_DEPRECATIONS 1
+
+#if defined(__GNUC__) && !defined(V8_DISABLE_DEPRECATIONS)
+#define V8_DEPRECATED(func) func __attribute__ ((deprecated))
+#elif defined(_MSC_VER) && !defined(V8_DISABLE_DEPRECATIONS)
+#define V8_DEPRECATED(func) __declspec(deprecated) func
+#else
+#define V8_DEPRECATED(func) func
+#endif
+
/**
* The v8 JavaScript engine.
*/
@@ -1601,16 +1612,41 @@
/** Gets the number of internal fields for this Object. */
V8EXPORT int InternalFieldCount();
- /** Gets the value in an internal field. */
+
+ /** Gets the value from an internal field. */
inline Local<Value> GetInternalField(int index);
+
/** Sets the value in an internal field. */
V8EXPORT void SetInternalField(int index, Handle<Value> value);
- /** Gets a native pointer from an internal field. */
- inline void* GetPointerFromInternalField(int index);
+ /**
+ * Gets a native pointer from an internal field. Deprecated. If the pointer is
+ * always 2-byte-aligned, use GetAlignedPointerFromInternalField instead,
+ * otherwise use a combination of GetInternalField, External::Cast and
+ * External::Value.
+ */
+ V8EXPORT V8_DEPRECATED(void* GetPointerFromInternalField(int index));
- /** Sets a native pointer in an internal field. */
- V8EXPORT void SetPointerInInternalField(int index, void* value);
+ /**
+ * Sets a native pointer in an internal field. Deprecated. If the pointer is
+ * always 2-byte aligned, use SetAlignedPointerInInternalField instead,
+ * otherwise use a combination of External::New and SetInternalField.
+ */
+ inline V8_DEPRECATED(void SetPointerInInternalField(int index, void* value));
+
+ /**
+ * Gets a 2-byte-aligned native pointer from an internal field. This field
+ * must have been set by SetAlignedPointerInInternalField, everything else
+ * leads to undefined behavior.
+ */
+ inline void* GetAlignedPointerFromInternalField(int index);
+
+ /**
+ * Sets a 2-byte-aligned native pointer in an internal field. To retrieve such
+ * a field, GetAlignedPointerFromInternalField must be used, everything else
+ * leads to undefined behavior.
+ */
+ V8EXPORT void SetAlignedPointerInInternalField(int index, void* value);
// Testers for local properties.
V8EXPORT bool HasOwnProperty(Handle<String> key);
@@ -1741,14 +1777,8 @@
private:
V8EXPORT Object();
V8EXPORT static void CheckCast(Value* obj);
- V8EXPORT Local<Value> CheckedGetInternalField(int index);
- V8EXPORT void* SlowGetPointerFromInternalField(int index);
-
- /**
- * If quick access to the internal field is possible this method
- * returns the value. Otherwise an empty handle is returned.
- */
- inline Local<Value> UncheckedGetInternalField(int index);
+ V8EXPORT Local<Value> SlowGetInternalField(int index);
+ V8EXPORT void* SlowGetAlignedPointerFromInternalField(int index);
};
@@ -1959,29 +1989,22 @@
/**
- * A JavaScript value that wraps a C++ void*. This type of value is
- * mainly used to associate C++ data structures with JavaScript
- * objects.
- *
- * The Wrap function V8 will return the most optimal Value object wrapping the
- * C++ void*. The type of the value is not guaranteed to be an External object
- * and no assumptions about its type should be made. To access the wrapped
- * value Unwrap should be used, all other operations on that object will lead
- * to unpredictable results.
+ * A JavaScript value that wraps a C++ void*. This type of value is mainly used
+ * to associate C++ data structures with JavaScript objects.
*/
class External : public Value {
public:
- V8EXPORT static Local<Value> Wrap(void* data);
- static inline void* Unwrap(Handle<Value> obj);
+ /** Deprecated, use New instead. */
+ V8_DEPRECATED(static inline Local<Value> Wrap(void* value));
+
+ /** Deprecated, use a combination of Cast and Value instead. */
+ V8_DEPRECATED(static inline void* Unwrap(Handle<Value> obj));
V8EXPORT static Local<External> New(void* value);
static inline External* Cast(Value* obj);
V8EXPORT void* Value() const;
private:
- V8EXPORT External();
V8EXPORT static void CheckCast(v8::Value* obj);
- static inline void* QuickUnwrap(Handle<v8::Value> obj);
- V8EXPORT static void* FullUnwrap(Handle<v8::Value> obj);
};
@@ -3770,12 +3793,45 @@
static bool InContext();
/**
- * Associate an additional data object with the context. This is mainly used
- * with the debugger to provide additional information on the context through
- * the debugger API.
+ * Gets embedder data with index 0. Deprecated, use GetEmbedderData with index
+ * 0 instead.
*/
- void SetData(Handle<Value> data);
- Local<Value> GetData();
+ V8_DEPRECATED(inline Local<Value> GetData());
+
+ /**
+ * Sets embedder data with index 0. Deprecated, use SetEmbedderData with index
+ * 0 instead.
+ */
+ V8_DEPRECATED(inline void SetData(Handle<Value> value));
+
+ /**
+ * Gets the embedder data with the given index, which must have been set by a
+ * previous call to SetEmbedderData with the same index. Note that index 0
+ * currently has a special meaning for Chrome's debugger.
+ */
+ inline Local<Value> GetEmbedderData(int index);
+
+ /**
+ * Sets the embedder data with the given index, growing the data as
+ * needed. Note that index 0 currently has a special meaning for Chrome's
+ * debugger.
+ */
+ void SetEmbedderData(int index, Handle<Value> value);
+
+ /**
+ * Gets a 2-byte-aligned native pointer from the embedder data with the given
+ * index, which must have bees set by a previous call to
+ * SetAlignedPointerInEmbedderData with the same index. Note that index 0
+ * currently has a special meaning for Chrome's debugger.
+ */
+ inline void* GetAlignedPointerFromEmbedderData(int index);
+
+ /**
+ * Sets a 2-byte-aligned native pointer in the embedder data with the given
+ * index, growing the data as needed. Note that index 0 currently has a
+ * special meaning for Chrome's debugger.
+ */
+ void SetAlignedPointerInEmbedderData(int index, void* value);
/**
* Control whether code generation from strings is allowed. Calling
@@ -3824,6 +3880,9 @@
friend class Script;
friend class Object;
friend class Function;
+
+ Local<Value> SlowGetEmbedderData(int index);
+ void* SlowGetAlignedPointerFromEmbedderData(int index);
};
@@ -4057,11 +4116,6 @@
// Throw away top 32 bits and shift down (requires >> to be sign extending).
return static_cast<int>(reinterpret_cast<intptr_t>(value)) >> shift_bits;
}
-
- // For 32-bit systems any 2 bytes aligned pointer can be encoded as smi
- // with a plain reinterpret_cast.
- static const uintptr_t kEncodablePointerMask = 0x1;
- static const int kPointerToSmiShift = 0;
};
// Smi constants for 64-bit systems.
@@ -4073,26 +4127,11 @@
// Shift down and throw away top 32 bits.
return static_cast<int>(reinterpret_cast<intptr_t>(value) >> shift_bits);
}
-
- // To maximize the range of pointers that can be encoded
- // in the available 32 bits, we require them to be 8 bytes aligned.
- // This gives 2 ^ (32 + 3) = 32G address space covered.
- // It might be not enough to cover stack allocated objects on some platforms.
- static const int kPointerAlignment = 3;
-
- static const uintptr_t kEncodablePointerMask =
- ~(uintptr_t(0xffffffff) << kPointerAlignment);
-
- static const int kPointerToSmiShift =
- kSmiTagSize + kSmiShiftSize - kPointerAlignment;
};
typedef SmiTagging<kApiPointerSize> PlatformSmiTagging;
const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
-const uintptr_t kEncodablePointerMask =
- PlatformSmiTagging::kEncodablePointerMask;
-const int kPointerToSmiShift = PlatformSmiTagging::kPointerToSmiShift;
/**
* This class exports constants and functionality from within v8 that
@@ -4110,6 +4149,9 @@
static const int kOddballKindOffset = 3 * kApiPointerSize;
static const int kForeignAddressOffset = kApiPointerSize;
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
+ static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
+ static const int kContextHeaderSize = 2 * kApiPointerSize;
+ static const int kContextEmbedderDataIndex = 54;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
@@ -4122,7 +4164,7 @@
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptySymbolRootIndex = 118;
+ static const int kEmptySymbolRootIndex = 119;
static const int kJSObjectType = 0xaa;
static const int kFirstNonstringType = 0x80;
@@ -4137,10 +4179,6 @@
kHeapObjectTag);
}
- static inline bool HasSmiTag(internal::Object* value) {
- return ((reinterpret_cast<intptr_t>(value) & kSmiTagMask) == kSmiTag);
- }
-
static inline int SmiValue(internal::Object* value) {
return PlatformSmiTagging::SmiToInt(value);
}
@@ -4156,21 +4194,6 @@
return SmiValue(ReadField<O*>(obj, kOddballKindOffset));
}
- static inline void* GetExternalPointerFromSmi(internal::Object* value) {
- const uintptr_t address = reinterpret_cast<uintptr_t>(value);
- return reinterpret_cast<void*>(address >> kPointerToSmiShift);
- }
-
- static inline void* GetExternalPointer(internal::Object* obj) {
- if (HasSmiTag(obj)) {
- return GetExternalPointerFromSmi(obj);
- } else if (GetInstanceType(obj) == kForeignType) {
- return ReadField<void*>(obj, kForeignAddressOffset);
- } else {
- return NULL;
- }
- }
-
static inline bool IsExternalTwoByteString(int instance_type) {
int representation = (instance_type & kFullStringRepresentationMask);
return representation == kExternalTwoByteRepresentationTag;
@@ -4204,6 +4227,19 @@
return *reinterpret_cast<T*>(addr);
}
+ template <typename T>
+ static inline T ReadEmbedderData(Context* context, int index) {
+ typedef internal::Object O;
+ typedef internal::Internals I;
+ O* ctx = *reinterpret_cast<O**>(context);
+ int embedder_data_offset = I::kContextHeaderSize +
+ (internal::kApiPointerSize * I::kContextEmbedderDataIndex);
+ O* embedder_data = I::ReadField<O*>(ctx, embedder_data_offset);
+ int value_offset =
+ I::kFixedArrayHeaderSize + (internal::kApiPointerSize * index);
+ return I::ReadField<T>(embedder_data, value_offset);
+ }
+
static inline bool CanCastToHeapObject(void* o) { return false; }
static inline bool CanCastToHeapObject(Context* o) { return true; }
static inline bool CanCastToHeapObject(String* o) { return true; }
@@ -4418,63 +4454,40 @@
Local<Value> Object::GetInternalField(int index) {
#ifndef V8_ENABLE_CHECKS
- Local<Value> quick_result = UncheckedGetInternalField(index);
- if (!quick_result.IsEmpty()) return quick_result;
-#endif
- return CheckedGetInternalField(index);
-}
-
-
-Local<Value> Object::UncheckedGetInternalField(int index) {
typedef internal::Object O;
typedef internal::Internals I;
O* obj = *reinterpret_cast<O**>(this);
+ // Fast path: If the object is a plain JSObject, which is the common case, we
+ // know where to find the internal fields and can return the value directly.
if (I::GetInstanceType(obj) == I::kJSObjectType) {
- // If the object is a plain JSObject, which is the common case,
- // we know where to find the internal fields and can return the
- // value directly.
int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index);
O* value = I::ReadField<O*>(obj, offset);
O** result = HandleScope::CreateHandle(value);
return Local<Value>(reinterpret_cast<Value*>(result));
- } else {
- return Local<Value>();
}
-}
-
-
-void* External::Unwrap(Handle<v8::Value> obj) {
-#ifdef V8_ENABLE_CHECKS
- return FullUnwrap(obj);
-#else
- return QuickUnwrap(obj);
#endif
+ return SlowGetInternalField(index);
}
-void* External::QuickUnwrap(Handle<v8::Value> wrapper) {
- typedef internal::Object O;
- O* obj = *reinterpret_cast<O**>(const_cast<v8::Value*>(*wrapper));
- return internal::Internals::GetExternalPointer(obj);
+void Object::SetPointerInInternalField(int index, void* value) {
+ SetInternalField(index, External::New(value));
}
-void* Object::GetPointerFromInternalField(int index) {
+void* Object::GetAlignedPointerFromInternalField(int index) {
+#ifndef V8_ENABLE_CHECKS
typedef internal::Object O;
typedef internal::Internals I;
-
O* obj = *reinterpret_cast<O**>(this);
-
+ // Fast path: If the object is a plain JSObject, which is the common case, we
+ // know where to find the internal fields and can return the value directly.
if (I::GetInstanceType(obj) == I::kJSObjectType) {
- // If the object is a plain JSObject, which is the common case,
- // we know where to find the internal fields and can return the
- // value directly.
int offset = I::kJSObjectHeaderSize + (internal::kApiPointerSize * index);
- O* value = I::ReadField<O*>(obj, offset);
- return I::GetExternalPointer(value);
+ return I::ReadField<void*>(obj, offset);
}
-
- return SlowGetPointerFromInternalField(index);
+#endif
+ return SlowGetAlignedPointerFromInternalField(index);
}
@@ -4666,6 +4679,16 @@
}
+Local<Value> External::Wrap(void* value) {
+ return External::New(value);
+}
+
+
+void* External::Unwrap(Handle<v8::Value> obj) {
+ return External::Cast(*obj)->Value();
+}
+
+
External* External::Cast(v8::Value* value) {
#ifdef V8_ENABLE_CHECKS
CheckCast(value);
@@ -4742,6 +4765,37 @@
}
+Local<Value> Context::GetData() {
+ return GetEmbedderData(0);
+}
+
+void Context::SetData(Handle<Value> data) {
+ SetEmbedderData(0, data);
+}
+
+
+Local<Value> Context::GetEmbedderData(int index) {
+#ifndef V8_ENABLE_CHECKS
+ typedef internal::Object O;
+ typedef internal::Internals I;
+ O** result = HandleScope::CreateHandle(I::ReadEmbedderData<O*>(this, index));
+ return Local<Value>(reinterpret_cast<Value*>(result));
+#else
+ return SlowGetEmbedderData(index);
+#endif
+}
+
+
+void* Context::GetAlignedPointerFromEmbedderData(int index) {
+#ifndef V8_ENABLE_CHECKS
+ typedef internal::Internals I;
+ return I::ReadEmbedderData<void*>(this, index);
+#else
+ return SlowGetAlignedPointerFromEmbedderData(index);
+#endif
+}
+
+
/**
* \example shell.cc
* A simple shell that takes a list of expressions on the
diff --git a/samples/shell.cc b/samples/shell.cc
index 821ef75..62f4045 100644
--- a/samples/shell.cc
+++ b/samples/shell.cc
@@ -72,7 +72,7 @@
v8::HandleScope handle_scope;
v8::Persistent<v8::Context> context = CreateShellContext();
if (context.IsEmpty()) {
- printf("Error creating context\n");
+ fprintf(stderr, "Error creating context\n");
return 1;
}
context->Enter();
@@ -226,7 +226,8 @@
// alone JavaScript engines.
continue;
} else if (strncmp(str, "--", 2) == 0) {
- printf("Warning: unknown flag %s.\nTry --help for options\n", str);
+ fprintf(stderr,
+ "Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
// Execute argument given to -e option directly.
v8::Handle<v8::String> file_name = v8::String::New("unnamed");
@@ -237,7 +238,7 @@
v8::Handle<v8::String> file_name = v8::String::New(str);
v8::Handle<v8::String> source = ReadFile(str);
if (source.IsEmpty()) {
- printf("Error reading '%s'\n", str);
+ fprintf(stderr, "Error reading '%s'\n", str);
continue;
}
if (!ExecuteString(source, file_name, false, true)) return 1;
@@ -249,20 +250,20 @@
// The read-eval-execute loop of the shell.
void RunShell(v8::Handle<v8::Context> context) {
- printf("V8 version %s [sample shell]\n", v8::V8::GetVersion());
+ fprintf(stderr, "V8 version %s [sample shell]\n", v8::V8::GetVersion());
static const int kBufferSize = 256;
// Enter the execution environment before evaluating any code.
v8::Context::Scope context_scope(context);
v8::Local<v8::String> name(v8::String::New("(shell)"));
while (true) {
char buffer[kBufferSize];
- printf("> ");
+ fprintf(stderr, "> ");
char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break;
v8::HandleScope handle_scope;
ExecuteString(v8::String::New(str), name, true, true);
}
- printf("\n");
+ fprintf(stderr, "\n");
}
@@ -310,31 +311,31 @@
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
- printf("%s\n", exception_string);
+ fprintf(stderr, "%s\n", exception_string);
} else {
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(message->GetScriptResourceName());
const char* filename_string = ToCString(filename);
int linenum = message->GetLineNumber();
- printf("%s:%i: %s\n", filename_string, linenum, exception_string);
+ fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
// Print line of source code.
v8::String::Utf8Value sourceline(message->GetSourceLine());
const char* sourceline_string = ToCString(sourceline);
- printf("%s\n", sourceline_string);
+ fprintf(stderr, "%s\n", sourceline_string);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i = 0; i < start; i++) {
- printf(" ");
+ fprintf(stderr, " ");
}
int end = message->GetEndColumn();
for (int i = start; i < end; i++) {
- printf("^");
+ fprintf(stderr, "^");
}
- printf("\n");
+ fprintf(stderr, "\n");
v8::String::Utf8Value stack_trace(try_catch->StackTrace());
if (stack_trace.length() > 0) {
const char* stack_trace_string = ToCString(stack_trace);
- printf("%s\n", stack_trace_string);
+ fprintf(stderr, "%s\n", stack_trace_string);
}
}
}
diff --git a/src/api.cc b/src/api.cc
index 4820f9d..a6619f1 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -25,6 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Deprecated API entries use other deprecated entries, too.
+#define V8_DISABLE_DEPRECATIONS 1
+
#include "api.h"
#include <math.h> // For isnan.
@@ -810,33 +813,77 @@
}
-void Context::SetData(v8::Handle<Value> data) {
- i::Handle<i::Context> env = Utils::OpenHandle(this);
- i::Isolate* isolate = env->GetIsolate();
- if (IsDeadCheck(isolate, "v8::Context::SetData()")) return;
- i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
- ASSERT(env->IsNativeContext());
- if (env->IsNativeContext()) {
- env->set_data(*raw_data);
- }
+static void* DecodeSmiToAligned(i::Object* value, const char* location) {
+ ApiCheck(value->IsSmi(), location, "Not a Smi");
+ return reinterpret_cast<void*>(value);
}
-v8::Local<v8::Value> Context::GetData() {
- i::Handle<i::Context> env = Utils::OpenHandle(this);
- i::Isolate* isolate = env->GetIsolate();
- if (IsDeadCheck(isolate, "v8::Context::GetData()")) {
- return Local<Value>();
+static i::Smi* EncodeAlignedAsSmi(void* value, const char* location) {
+ i::Smi* smi = reinterpret_cast<i::Smi*>(value);
+ ApiCheck(smi->IsSmi(), location, "Pointer is not aligned");
+ return smi;
+}
+
+
+static i::Handle<i::FixedArray> EmbedderDataFor(Context* context,
+ int index,
+ bool can_grow,
+ const char* location) {
+ i::Handle<i::Context> env = Utils::OpenHandle(context);
+ bool ok = !IsDeadCheck(env->GetIsolate(), location) &&
+ ApiCheck(env->IsNativeContext(), location, "Not a native context") &&
+ ApiCheck(index >= 0, location, "Negative index");
+ if (!ok) return i::Handle<i::FixedArray>();
+ i::Handle<i::FixedArray> data(env->embedder_data());
+ if (index < data->length()) return data;
+ if (!can_grow) {
+ Utils::ReportApiFailure(location, "Index too large");
+ return i::Handle<i::FixedArray>();
}
- ASSERT(env->IsNativeContext());
- if (!env->IsNativeContext()) {
- return Local<Value>();
- }
- i::Handle<i::Object> result(env->data(), isolate);
+ int new_size = i::Max(index, data->length() << 1) + 1;
+ data = env->GetIsolate()->factory()->CopySizeFixedArray(data, new_size);
+ env->set_embedder_data(*data);
+ return data;
+}
+
+
+v8::Local<v8::Value> Context::SlowGetEmbedderData(int index) {
+ const char* location = "v8::Context::GetEmbedderData()";
+ i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, false, location);
+ if (data.is_null()) return Local<Value>();
+ i::Handle<i::Object> result(data->get(index), data->GetIsolate());
return Utils::ToLocal(result);
}
+void Context::SetEmbedderData(int index, v8::Handle<Value> value) {
+ const char* location = "v8::Context::SetEmbedderData()";
+ i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, true, location);
+ if (data.is_null()) return;
+ i::Handle<i::Object> val = Utils::OpenHandle(*value);
+ data->set(index, *val);
+ ASSERT_EQ(*Utils::OpenHandle(*value),
+ *Utils::OpenHandle(*GetEmbedderData(index)));
+}
+
+
+void* Context::SlowGetAlignedPointerFromEmbedderData(int index) {
+ const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()";
+ i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, false, location);
+ if (data.is_null()) return NULL;
+ return DecodeSmiToAligned(data->get(index), location);
+}
+
+
+void Context::SetAlignedPointerInEmbedderData(int index, void* value) {
+ const char* location = "v8::Context::SetAlignedPointerInEmbedderData()";
+ i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, true, location);
+ data->set(index, EncodeAlignedAsSmi(value, location));
+ ASSERT_EQ(value, GetAlignedPointerFromEmbedderData(index));
+}
+
+
i::Object** v8::HandleScope::RawClose(i::Object** value) {
if (!ApiCheck(!is_closed_,
"v8::HandleScope::Close()",
@@ -2235,7 +2282,7 @@
if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsExternal()")) {
return false;
}
- return Utils::OpenHandle(this)->IsForeign();
+ return Utils::OpenHandle(this)->IsExternal();
}
@@ -2309,7 +2356,11 @@
static bool CheckConstructor(i::Isolate* isolate,
i::Handle<i::JSObject> obj,
const char* class_name) {
- return obj->map()->constructor() == LookupBuiltin(isolate, class_name);
+ i::Object* constr = obj->map()->constructor();
+ if (!constr->IsJSFunction()) return false;
+ i::JSFunction* func = i::JSFunction::cast(constr);
+ return func->shared()->native() &&
+ constr == LookupBuiltin(isolate, class_name);
}
@@ -2464,8 +2515,7 @@
void External::CheckCast(v8::Value* that) {
if (IsDeadCheck(i::Isolate::Current(), "v8::External::Cast()")) return;
- i::Handle<i::Object> obj = Utils::OpenHandle(that);
- ApiCheck(obj->IsForeign(),
+ ApiCheck(Utils::OpenHandle(that)->IsExternal(),
"v8::External::Cast()",
"Could not convert to external");
}
@@ -4229,75 +4279,65 @@
}
-Local<Value> v8::Object::CheckedGetInternalField(int index) {
+static bool InternalFieldOK(i::Handle<i::JSObject> obj,
+ int index,
+ const char* location) {
+ return !IsDeadCheck(obj->GetIsolate(), location) &&
+ ApiCheck(index < obj->GetInternalFieldCount(),
+ location,
+ "Internal field out of bounds");
+}
+
+
+Local<Value> v8::Object::SlowGetInternalField(int index) {
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
- if (IsDeadCheck(obj->GetIsolate(), "v8::Object::GetInternalField()")) {
- return Local<Value>();
- }
- if (!ApiCheck(index < obj->GetInternalFieldCount(),
- "v8::Object::GetInternalField()",
- "Reading internal field out of bounds")) {
- return Local<Value>();
- }
- i::Handle<i::Object> value(obj->GetInternalField(index));
- Local<Value> result = Utils::ToLocal(value);
-#ifdef DEBUG
- Local<Value> unchecked = UncheckedGetInternalField(index);
- ASSERT(unchecked.IsEmpty() || (unchecked == result));
-#endif
- return result;
+ const char* location = "v8::Object::GetInternalField()";
+ if (!InternalFieldOK(obj, index, location)) return Local<Value>();
+ i::Handle<i::Object> value(obj->GetInternalField(index), obj->GetIsolate());
+ return Utils::ToLocal(value);
}
void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
- i::Isolate* isolate = obj->GetIsolate();
- if (IsDeadCheck(isolate, "v8::Object::SetInternalField()")) {
- return;
- }
- if (!ApiCheck(index < obj->GetInternalFieldCount(),
- "v8::Object::SetInternalField()",
- "Writing internal field out of bounds")) {
- return;
- }
- ENTER_V8(isolate);
+ const char* location = "v8::Object::SetInternalField()";
+ if (!InternalFieldOK(obj, index, location)) return;
i::Handle<i::Object> val = Utils::OpenHandle(*value);
obj->SetInternalField(index, *val);
+ ASSERT_EQ(value, GetInternalField(index));
}
-static bool CanBeEncodedAsSmi(void* ptr) {
- const uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
- return ((address & i::kEncodablePointerMask) == 0);
+void* v8::Object::SlowGetAlignedPointerFromInternalField(int index) {
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ const char* location = "v8::Object::GetAlignedPointerFromInternalField()";
+ if (!InternalFieldOK(obj, index, location)) return NULL;
+ return DecodeSmiToAligned(obj->GetInternalField(index), location);
}
-static i::Smi* EncodeAsSmi(void* ptr) {
- ASSERT(CanBeEncodedAsSmi(ptr));
- const uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
- i::Smi* result = reinterpret_cast<i::Smi*>(address << i::kPointerToSmiShift);
- ASSERT(i::Internals::HasSmiTag(result));
- ASSERT_EQ(result, i::Smi::FromInt(result->value()));
- ASSERT_EQ(ptr, i::Internals::GetExternalPointerFromSmi(result));
- return result;
+void v8::Object::SetAlignedPointerInInternalField(int index, void* value) {
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ const char* location = "v8::Object::SetAlignedPointerInInternalField()";
+ if (!InternalFieldOK(obj, index, location)) return;
+ obj->SetInternalField(index, EncodeAlignedAsSmi(value, location));
+ ASSERT_EQ(value, GetAlignedPointerFromInternalField(index));
}
-void v8::Object::SetPointerInInternalField(int index, void* value) {
- i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
- ENTER_V8(isolate);
- if (CanBeEncodedAsSmi(value)) {
- Utils::OpenHandle(this)->SetInternalField(index, EncodeAsSmi(value));
- } else {
- HandleScope scope;
- i::Handle<i::Foreign> foreign =
- isolate->factory()->NewForeign(
- reinterpret_cast<i::Address>(value), i::TENURED);
- if (!foreign.is_null()) {
- Utils::OpenHandle(this)->SetInternalField(index, *foreign);
- }
- }
- ASSERT_EQ(value, GetPointerFromInternalField(index));
+static void* ExternalValue(i::Object* obj) {
+ // Obscure semantics for undefined, but somehow checked in our unit tests...
+ if (obj->IsUndefined()) return NULL;
+ i::Object* foreign = i::JSObject::cast(obj)->GetInternalField(0);
+ return i::Foreign::cast(foreign)->foreign_address();
+}
+
+
+void* Object::GetPointerFromInternalField(int index) {
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ const char* location = "v8::Object::GetPointerFromInternalField()";
+ if (!InternalFieldOK(obj, index, location)) return NULL;
+ return ExternalValue(obj->GetInternalField(index));
}
@@ -4736,74 +4776,20 @@
}
-static Local<External> ExternalNewImpl(void* data) {
- return Utils::ToLocal(FACTORY->NewForeign(static_cast<i::Address>(data)));
-}
-
-static void* ExternalValueImpl(i::Handle<i::Object> obj) {
- return reinterpret_cast<void*>(i::Foreign::cast(*obj)->foreign_address());
-}
-
-
-Local<Value> v8::External::Wrap(void* data) {
- i::Isolate* isolate = i::Isolate::Current();
- STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
- EnsureInitializedForIsolate(isolate, "v8::External::Wrap()");
- LOG_API(isolate, "External::Wrap");
- ENTER_V8(isolate);
-
- v8::Local<v8::Value> result = CanBeEncodedAsSmi(data)
- ? Utils::ToLocal(i::Handle<i::Object>(EncodeAsSmi(data)))
- : v8::Local<v8::Value>(ExternalNewImpl(data));
-
- ASSERT_EQ(data, Unwrap(result));
- return result;
-}
-
-
-void* v8::Object::SlowGetPointerFromInternalField(int index) {
- i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
- i::Object* value = obj->GetInternalField(index);
- if (value->IsSmi()) {
- return i::Internals::GetExternalPointerFromSmi(value);
- } else if (value->IsForeign()) {
- return reinterpret_cast<void*>(i::Foreign::cast(value)->foreign_address());
- } else {
- return NULL;
- }
-}
-
-
-void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) {
- if (IsDeadCheck(i::Isolate::Current(), "v8::External::Unwrap()")) return 0;
- i::Handle<i::Object> obj = Utils::OpenHandle(*wrapper);
- void* result;
- if (obj->IsSmi()) {
- result = i::Internals::GetExternalPointerFromSmi(*obj);
- } else if (obj->IsForeign()) {
- result = ExternalValueImpl(obj);
- } else {
- result = NULL;
- }
- ASSERT_EQ(result, QuickUnwrap(wrapper));
- return result;
-}
-
-
-Local<External> v8::External::New(void* data) {
- STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
+Local<External> v8::External::New(void* value) {
+ STATIC_ASSERT(sizeof(value) == sizeof(i::Address));
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::External::New()");
LOG_API(isolate, "External::New");
ENTER_V8(isolate);
- return ExternalNewImpl(data);
+ i::Handle<i::JSObject> external = isolate->factory()->NewExternal(value);
+ return Utils::ExternalToLocal(external);
}
void* External::Value() const {
- if (IsDeadCheck(i::Isolate::Current(), "v8::External::Value()")) return 0;
- i::Handle<i::Object> obj = Utils::OpenHandle(this);
- return ExternalValueImpl(obj);
+ if (IsDeadCheck(i::Isolate::Current(), "v8::External::Value()")) return NULL;
+ return ExternalValue(*Utils::OpenHandle(this));
}
diff --git a/src/api.h b/src/api.h
index 7197b6c..ca2240b 100644
--- a/src/api.h
+++ b/src/api.h
@@ -201,8 +201,6 @@
v8::internal::Handle<v8::internal::JSObject> obj);
static inline Local<Array> ToLocal(
v8::internal::Handle<v8::internal::JSArray> obj);
- static inline Local<External> ToLocal(
- v8::internal::Handle<v8::internal::Foreign> obj);
static inline Local<Message> MessageToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<StackTrace> StackTraceToLocal(
@@ -225,6 +223,8 @@
v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj);
static inline Local<TypeSwitch> ToLocal(
v8::internal::Handle<v8::internal::TypeSwitchInfo> obj);
+ static inline Local<External> ExternalToLocal(
+ v8::internal::Handle<v8::internal::JSObject> obj);
#define DECLARE_OPEN_HANDLE(From, To) \
static inline v8::internal::Handle<v8::internal::To> \
@@ -268,7 +268,6 @@
MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
-MAKE_TO_LOCAL(ToLocal, Foreign, External)
MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate)
MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate)
MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature)
@@ -280,6 +279,7 @@
MAKE_TO_LOCAL(NumberToLocal, Object, Number)
MAKE_TO_LOCAL(IntegerToLocal, Object, Integer)
MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32)
+MAKE_TO_LOCAL(ExternalToLocal, JSObject, External)
#undef MAKE_TO_LOCAL
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 17f3325..ff6da03 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1881,7 +1881,6 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
-
LOperand* external_pointer = UseRegister(instr->elements());
result = new(zone()) LLoadKeyed(external_pointer, key);
}
@@ -1906,22 +1905,32 @@
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- LOperand* elements = UseRegisterAtStart(instr->elements());
- LOperand* key;
- LOperand* val;
- if (instr->NeedsWriteBarrier()) {
- key = UseTempRegister(instr->key());
- val = UseTempRegister(instr->value());
- } else {
- key = UseRegisterOrConstantAtStart(instr->key());
- val = UseRegisterAtStart(instr->value());
- }
+ ElementsKind elements_kind = instr->elements_kind();
+ bool needs_write_barrier = instr->NeedsWriteBarrier();
+ LOperand* key = needs_write_barrier
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
+ bool val_is_temp_register =
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT_ELEMENTS;
+ LOperand* val = val_is_temp_register || needs_write_barrier
+ ? UseTempRegister(instr->value())
+ : UseRegister(instr->value());
-#ifdef DEBUG
+ LStoreKeyed* result = NULL;
if (!instr->is_external()) {
ASSERT(instr->elements()->representation().IsTagged());
+
+ LOperand* object = NULL;
+ if (instr->value()->representation().IsDouble()) {
+ object = UseRegisterAtStart(instr->elements());
+ } else {
+ ASSERT(instr->value()->representation().IsTagged());
+ object = UseTempRegister(instr->elements());
+ }
+
+ result = new(zone()) LStoreKeyed(object, key, val);
} else {
- ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(instr->value()->representation().IsInteger32() &&
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
@@ -1930,10 +1939,11 @@
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->elements()->representation().IsExternal());
- }
-#endif
- LStoreKeyed* result = new(zone()) LStoreKeyed(elements, key, val);
+ LOperand* external_pointer = UseRegister(instr->elements());
+ result = new(zone()) LStoreKeyed(external_pointer, key, val);
+ }
+
ASSERT(result != NULL);
return result;
}
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 9fc39d4..b039b3d 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -327,18 +327,23 @@
Register dst,
Register src,
Handle<JSObject> holder,
- int index) {
- // Adjust for the number of properties stored in the holder.
- index -= holder->map()->inobject_properties();
- if (index < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (index * kPointerSize);
+ PropertyIndex index) {
+ if (index.is_header_index()) {
+ int offset = index.header_index() * kPointerSize;
__ ldr(dst, FieldMemOperand(src, offset));
} else {
- // Calculate the offset into the properties array.
- int offset = index * kPointerSize + FixedArray::kHeaderSize;
- __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
- __ ldr(dst, FieldMemOperand(dst, offset));
+ // Adjust for the number of properties stored in the holder.
+ int slot = index.field_index() - holder->map()->inobject_properties();
+ if (slot < 0) {
+ // Get the property straight out of the holder.
+ int offset = holder->map()->instance_size() + (slot * kPointerSize);
+ __ ldr(dst, FieldMemOperand(src, offset));
+ } else {
+ // Calculate the offset into the properties array.
+ int offset = slot * kPointerSize + FixedArray::kHeaderSize;
+ __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
+ __ ldr(dst, FieldMemOperand(dst, offset));
+ }
}
}
@@ -1196,7 +1201,7 @@
Register scratch1,
Register scratch2,
Register scratch3,
- int index,
+ PropertyIndex index,
Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
@@ -1545,7 +1550,7 @@
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name) {
// ----------- S t a t e -------------
// -- r2 : name
@@ -2912,7 +2917,7 @@
Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name) {
// ----------- S t a t e -------------
// -- r0 : receiver
@@ -3101,7 +3106,7 @@
Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- int index) {
+ PropertyIndex index) {
// ----------- S t a t e -------------
// -- lr : return address
// -- r0 : key
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index ffa5283..22c75a1 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1084,11 +1084,11 @@
LookupResult lookup(isolate);
result->LocalLookup(heap->callee_symbol(), &lookup);
ASSERT(lookup.IsField());
- ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsCalleeIndex);
+ ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsCalleeIndex);
result->LocalLookup(heap->length_symbol(), &lookup);
ASSERT(lookup.IsField());
- ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex);
+ ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex);
ASSERT(result->map()->inobject_properties() > Heap::kArgumentsCalleeIndex);
ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);
@@ -1186,7 +1186,7 @@
LookupResult lookup(isolate);
result->LocalLookup(heap->length_symbol(), &lookup);
ASSERT(lookup.IsField());
- ASSERT(lookup.GetFieldIndex() == Heap::kArgumentsLengthIndex);
+ ASSERT(lookup.GetFieldIndex().field_index() == Heap::kArgumentsLengthIndex);
ASSERT(result->map()->inobject_properties() > Heap::kArgumentsLengthIndex);
@@ -1240,8 +1240,9 @@
// Initialize the out of memory slot.
native_context()->set_out_of_memory(heap->false_value());
- // Initialize the data slot.
- native_context()->set_data(heap->undefined_value());
+ // Initialize the embedder data slot.
+ Handle<FixedArray> embedder_data = factory->NewFixedArray(2);
+ native_context()->set_embedder_data(*embedder_data);
{
// Initialize the random seed slot.
diff --git a/src/compiler.cc b/src/compiler.cc
index 710c61e..4250de1 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -432,7 +432,9 @@
ASSERT(!isolate->native_context().is_null());
Handle<Script> script = info->script();
- script->set_context_data((*isolate->native_context())->data());
+ // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile?
+ FixedArray* array = isolate->native_context()->embedder_data();
+ script->set_context_data(array->get(0));
#ifdef ENABLE_DEBUGGER_SUPPORT
if (info->is_eval()) {
diff --git a/src/contexts.h b/src/contexts.h
index f44d15d..7a3ab49 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -152,7 +152,7 @@
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
V(MAP_CACHE_INDEX, Object, map_cache) \
- V(CONTEXT_DATA_INDEX, Object, data) \
+ V(EMBEDDER_DATA_INDEX, FixedArray, embedder_data) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
error_message_for_code_gen_from_strings) \
@@ -283,7 +283,7 @@
OPAQUE_REFERENCE_FUNCTION_INDEX,
CONTEXT_EXTENSION_FUNCTION_INDEX,
OUT_OF_MEMORY_INDEX,
- CONTEXT_DATA_INDEX,
+ EMBEDDER_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX,
TO_COMPLETE_PROPERTY_DESCRIPTOR_INDEX,
@@ -450,6 +450,9 @@
static bool IsBootstrappingOrValidParentContext(Object* object, Context* kid);
static bool IsBootstrappingOrGlobalObject(Object* object);
#endif
+
+ STATIC_CHECK(kHeaderSize == Internals::kContextHeaderSize);
+ STATIC_CHECK(EMBEDDER_DATA_INDEX == Internals::kContextEmbedderDataIndex);
};
} } // namespace v8::internal
diff --git a/src/factory.cc b/src/factory.cc
index a2bb939..32a1755 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -525,6 +525,12 @@
}
+Handle<FixedArray> Factory::CopySizeFixedArray(Handle<FixedArray> array,
+ int new_length) {
+ CALL_HEAP_FUNCTION(isolate(), array->CopySize(new_length), FixedArray);
+}
+
+
Handle<FixedDoubleArray> Factory::CopyFixedDoubleArray(
Handle<FixedDoubleArray> array) {
CALL_HEAP_FUNCTION(isolate(), array->Copy(), FixedDoubleArray);
@@ -870,6 +876,13 @@
}
+Handle<JSObject> Factory::NewExternal(void* value) {
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateExternal(value),
+ JSObject);
+}
+
+
Handle<Code> Factory::NewCode(const CodeDesc& desc,
Code::Flags flags,
Handle<Object> self_ref,
diff --git a/src/factory.h b/src/factory.h
index 51065aa..95a33f9 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -239,6 +239,9 @@
Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
+ Handle<FixedArray> CopySizeFixedArray(Handle<FixedArray> array,
+ int new_length);
+
Handle<FixedDoubleArray> CopyFixedDoubleArray(
Handle<FixedDoubleArray> array);
@@ -325,6 +328,8 @@
Handle<ScopeInfo> NewScopeInfo(int length);
+ Handle<JSObject> NewExternal(void* value);
+
Handle<Code> NewCode(const CodeDesc& desc,
Code::Flags flags,
Handle<Object> self_reference,
diff --git a/src/heap.cc b/src/heap.cc
index b85f1bc..5e760c3 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2578,6 +2578,14 @@
}
set_message_object_map(Map::cast(obj));
+ Map* external_map;
+ { MaybeObject* maybe_obj =
+ AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
+ if (!maybe_obj->To(&external_map)) return false;
+ }
+ external_map->set_is_extensible(false);
+ set_external_map(external_map);
+
ASSERT(!InNewSpace(empty_fixed_array()));
return true;
}
@@ -5217,6 +5225,20 @@
}
+MaybeObject* Heap::AllocateExternal(void* value) {
+ Foreign* foreign;
+ { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
+ if (!maybe_result->To(&foreign)) return maybe_result;
+ }
+ JSObject* external;
+ { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
+ if (!maybe_result->To(&external)) return maybe_result;
+ }
+ external->SetInternalField(0, foreign);
+ return external;
+}
+
+
MaybeObject* Heap::AllocateStruct(InstanceType type) {
Map* map;
switch (type) {
diff --git a/src/heap.h b/src/heap.h
index ae14302..eecb436 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -155,7 +155,8 @@
V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \
V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset) \
V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset) \
- V(JSObject, observation_state, ObservationState)
+ V(JSObject, observation_state, ObservationState) \
+ V(Map, external_map, ExternalMap)
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
@@ -665,6 +666,9 @@
// Allocates a serialized scope info.
MUST_USE_RESULT MaybeObject* AllocateScopeInfo(int length);
+ // Allocates an External object for v8's external API.
+ MUST_USE_RESULT MaybeObject* AllocateExternal(void* value);
+
// Allocates an empty PolymorphicCodeCache.
MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache();
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 676e73e..6e86d92 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2775,12 +2775,15 @@
void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
ElementsKind elements_kind = instr->elements_kind();
- if (ExternalArrayOpRequiresTemp<HLoadKeyed>(instr->hydrogen())) {
- __ SmiUntag(ToRegister(instr->key()));
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand() &&
+ ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
+ elements_kind)) {
+ __ SmiUntag(ToRegister(key));
}
Operand operand(BuildFastArrayOperand(
instr->elements(),
- instr->key(),
+ key,
instr->hydrogen()->key()->representation(),
elements_kind,
0,
@@ -3850,12 +3853,15 @@
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
ElementsKind elements_kind = instr->elements_kind();
- if (ExternalArrayOpRequiresTemp<HStoreKeyed>(instr->hydrogen())) {
- __ SmiUntag(ToRegister(instr->key()));
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand() &&
+ ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
+ elements_kind)) {
+ __ SmiUntag(ToRegister(key));
}
Operand operand(BuildFastArrayOperand(
instr->elements(),
- instr->key(),
+ key,
instr->hydrogen()->key()->representation(),
elements_kind,
0,
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index ba9c97e..4207410 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1933,14 +1933,17 @@
ASSERT(instr->key()->representation().IsInteger32() ||
instr->key()->representation().IsTagged());
ElementsKind elements_kind = instr->elements_kind();
- LOperand* elements = UseRegisterAtStart(instr->elements());
- LOperand* key = instr->is_external() &&
- ExternalArrayOpRequiresTemp<HLoadKeyed>(instr)
+ bool clobbers_key = ExternalArrayOpRequiresTemp(
+ instr->key()->representation(), elements_kind);
+ LOperand* key = clobbers_key
? UseTempRegister(instr->key())
: UseRegisterOrConstantAtStart(instr->key());
+ LLoadKeyed* result = NULL;
-#ifdef DEBUG
- if (instr->is_external()) {
+ if (!instr->is_external()) {
+ LOperand* obj = UseRegisterAtStart(instr->elements());
+ result = new(zone()) LLoadKeyed(obj, key);
+ } else {
ASSERT(
(instr->representation().IsInteger32() &&
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
@@ -1948,10 +1951,10 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
+ LOperand* external_pointer = UseRegister(instr->elements());
+ result = new(zone()) LLoadKeyed(external_pointer, key);
}
-#endif
- LLoadKeyed* result = new(zone()) LLoadKeyed(elements, key);
DefineAsRegister(result);
bool can_deoptimize = instr->RequiresHoleCheck() ||
(elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS);
@@ -1973,27 +1976,34 @@
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- ElementsKind elements_kind = instr->elements_kind();
- LOperand* elements;
- LOperand* val;
- LOperand* key;
+ LStoreKeyed* result = NULL;
if (!instr->is_external()) {
ASSERT(instr->elements()->representation().IsTagged());
ASSERT(instr->key()->representation().IsInteger32() ||
instr->key()->representation().IsTagged());
- if (instr->NeedsWriteBarrier() &&
- !IsFastDoubleElementsKind(elements_kind)) {
- val = UseTempRegister(instr->value());
- key = UseTempRegister(instr->key());
- elements = UseRegister(instr->elements());
+ if (instr->value()->representation().IsDouble()) {
+ LOperand* object = UseRegisterAtStart(instr->elements());
+ LOperand* val = UseTempRegister(instr->value());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+
+ result = new(zone()) LStoreKeyed(object, key, val);
} else {
- val = UseRegisterAtStart(instr->value());
- key = UseRegisterOrConstantAtStart(instr->key());
- elements = UseRegisterAtStart(instr->elements());
+ ASSERT(instr->value()->representation().IsTagged());
+ bool needs_write_barrier = instr->NeedsWriteBarrier();
+
+ LOperand* obj = UseRegister(instr->elements());
+ LOperand* val = needs_write_barrier
+ ? UseTempRegister(instr->value())
+ : UseRegisterAtStart(instr->value());
+ LOperand* key = needs_write_barrier
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
+ result = new(zone()) LStoreKeyed(obj, key, val);
}
} else {
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(instr->value()->representation().IsInteger32() &&
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
@@ -2003,25 +2013,26 @@
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->elements()->representation().IsExternal());
- if (ExternalArrayOpRequiresTemp<HStoreKeyed>(instr)) {
- key = UseTempRegister(instr->key());
- elements = UseRegister(instr->elements());
- } else {
- key = UseRegisterOrConstantAtStart(instr->key());
- elements = UseRegisterAtStart(instr->elements());
- }
-
+ LOperand* external_pointer = UseRegister(instr->elements());
// Determine if we need a byte register in this case for the value.
bool val_is_fixed_register =
elements_kind == EXTERNAL_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_PIXEL_ELEMENTS;
- val = val_is_fixed_register
+
+ LOperand* val = val_is_fixed_register
? UseFixed(instr->value(), eax)
: UseRegister(instr->value());
+ bool clobbers_key = ExternalArrayOpRequiresTemp(
+ instr->key()->representation(), elements_kind);
+ LOperand* key = clobbers_key
+ ? UseTempRegister(instr->key())
+ : UseRegisterOrConstantAtStart(instr->key());
+ result = new(zone()) LStoreKeyed(external_pointer,
+ key,
+ val);
}
- LStoreKeyed* result = new(zone()) LStoreKeyed(elements, key, val);
ASSERT(result != NULL);
return result;
}
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 18741d1..88b1ef0 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -1408,16 +1408,13 @@
};
-template <class T>
-inline static bool ExternalArrayOpRequiresTemp(T* value) {
- CHECK(value->IsLoadKeyed() || value->IsStoreKeyed());
- Representation key_representation = value->key()->representation();
- ElementsKind elements_kind = value->elements_kind();
-
+inline static bool ExternalArrayOpRequiresTemp(
+ Representation key_representation,
+ ElementsKind elements_kind) {
// Operations that require the key to be divided by two to be converted into
// an index cannot fold the scale operation into a load and need an extra
// temp register to do the work.
- return !value->IsConstant() && key_representation.IsTagged() &&
+ return key_representation.IsTagged() &&
(elements_kind == EXTERNAL_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS ||
elements_kind == EXTERNAL_PIXEL_ELEMENTS);
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 11efb72..127d16a 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -376,18 +376,23 @@
Register dst,
Register src,
Handle<JSObject> holder,
- int index) {
- // Adjust for the number of properties stored in the holder.
- index -= holder->map()->inobject_properties();
- if (index < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (index * kPointerSize);
+ PropertyIndex index) {
+ if (index.is_header_index()) {
+ int offset = index.header_index() * kPointerSize;
__ mov(dst, FieldOperand(src, offset));
} else {
- // Calculate the offset into the properties array.
- int offset = index * kPointerSize + FixedArray::kHeaderSize;
- __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
- __ mov(dst, FieldOperand(dst, offset));
+ // Adjust for the number of properties stored in the holder.
+ int slot = index.field_index() - holder->map()->inobject_properties();
+ if (slot < 0) {
+ // Get the property straight out of the holder.
+ int offset = holder->map()->instance_size() + (slot * kPointerSize);
+ __ mov(dst, FieldOperand(src, offset));
+ } else {
+ // Calculate the offset into the properties array.
+ int offset = slot * kPointerSize + FixedArray::kHeaderSize;
+ __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ __ mov(dst, FieldOperand(dst, offset));
+ }
}
}
@@ -1036,7 +1041,7 @@
Register scratch1,
Register scratch2,
Register scratch3,
- int index,
+ PropertyIndex index,
Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
@@ -1423,7 +1428,7 @@
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name) {
// ----------- S t a t e -------------
// -- ecx : name
@@ -2956,7 +2961,7 @@
Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name) {
// ----------- S t a t e -------------
// -- ecx : name
@@ -3156,7 +3161,7 @@
Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- int index) {
+ PropertyIndex index) {
// ----------- S t a t e -------------
// -- ecx : key
// -- edx : receiver
diff --git a/src/ic.cc b/src/ic.cc
index 5cc213f..1418f02 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -646,7 +646,7 @@
Handle<JSObject> holder(lookup->holder());
switch (lookup->type()) {
case FIELD: {
- int index = lookup->GetFieldIndex();
+ PropertyIndex index = lookup->GetFieldIndex();
return isolate()->stub_cache()->ComputeCallField(
argc, kind_, extra_state, name, object, holder, index);
}
@@ -1467,11 +1467,9 @@
Handle<Code> code;
switch (type) {
case FIELD:
- code = isolate()->stub_cache()->ComputeStoreField(name,
- receiver,
- lookup->GetFieldIndex(),
- Handle<Map>::null(),
- strict_mode);
+ code = isolate()->stub_cache()->ComputeStoreField(
+ name, receiver, lookup->GetFieldIndex().field_index(),
+ Handle<Map>::null(), strict_mode);
break;
case NORMAL:
if (receiver->IsGlobalObject()) {
@@ -1981,7 +1979,7 @@
switch (type) {
case FIELD:
code = isolate()->stub_cache()->ComputeKeyedStoreField(
- name, receiver, lookup->GetFieldIndex(),
+ name, receiver, lookup->GetFieldIndex().field_index(),
Handle<Map>::null(), strict_mode);
break;
case TRANSITION: {
diff --git a/src/isolate.cc b/src/isolate.cc
index 00979f7..85ae32a 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -553,7 +553,97 @@
}
-void Isolate::CaptureAndSetCurrentStackTraceFor(Handle<JSObject> error_object) {
+// Determines whether the given stack frame should be displayed in
+// a stack trace. The caller is the error constructor that asked
+// for the stack trace to be collected. The first time a construct
+// call to this function is encountered it is skipped. The seen_caller
+// in/out parameter is used to remember if the caller has been seen
+// yet.
+static bool IsVisibleInStackTrace(StackFrame* raw_frame,
+ Object* caller,
+ bool* seen_caller) {
+ // Only display JS frames.
+ if (!raw_frame->is_java_script()) return false;
+ JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
+ Object* raw_fun = frame->function();
+ // Not sure when this can happen but skip it just in case.
+ if (!raw_fun->IsJSFunction()) return false;
+ if ((raw_fun == caller) && !(*seen_caller)) {
+ *seen_caller = true;
+ return false;
+ }
+ // Skip all frames until we've seen the caller.
+ if (!(*seen_caller)) return false;
+ // Also, skip non-visible built-in functions and any call with the builtins
+ // object as receiver, so as to not reveal either the builtins object or
+ // an internal function.
+ // The --builtins-in-stack-traces command line flag allows including
+ // internal call sites in the stack trace for debugging purposes.
+ if (!FLAG_builtins_in_stack_traces) {
+ JSFunction* fun = JSFunction::cast(raw_fun);
+ if (frame->receiver()->IsJSBuiltinsObject() ||
+ (fun->IsBuiltin() && !fun->shared()->native())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
+ Handle<Object> caller,
+ int limit) {
+ limit = Max(limit, 0); // Ensure that limit is not negative.
+ int initial_size = Min(limit, 10);
+ Handle<FixedArray> elements =
+ factory()->NewFixedArrayWithHoles(initial_size * 4);
+
+ // If the caller parameter is a function we skip frames until we're
+ // under it before starting to collect.
+ bool seen_caller = !caller->IsJSFunction();
+ int cursor = 0;
+ int frames_seen = 0;
+ for (StackFrameIterator iter(this);
+ !iter.done() && frames_seen < limit;
+ iter.Advance()) {
+ StackFrame* raw_frame = iter.frame();
+ if (IsVisibleInStackTrace(raw_frame, *caller, &seen_caller)) {
+ frames_seen++;
+ JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
+ // Set initial size to the maximum inlining level + 1 for the outermost
+ // function.
+ List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
+ frame->Summarize(&frames);
+ for (int i = frames.length() - 1; i >= 0; i--) {
+ if (cursor + 4 > elements->length()) {
+ int new_capacity = JSObject::NewElementsCapacity(elements->length());
+ Handle<FixedArray> new_elements =
+ factory()->NewFixedArrayWithHoles(new_capacity);
+ for (int i = 0; i < cursor; i++) {
+ new_elements->set(i, elements->get(i));
+ }
+ elements = new_elements;
+ }
+ ASSERT(cursor + 4 <= elements->length());
+
+ Handle<Object> recv = frames[i].receiver();
+ Handle<JSFunction> fun = frames[i].function();
+ Handle<Code> code = frames[i].code();
+ Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
+ elements->set(cursor++, *recv);
+ elements->set(cursor++, *fun);
+ elements->set(cursor++, *code);
+ elements->set(cursor++, *offset);
+ }
+ }
+ }
+ Handle<JSArray> result = factory()->NewJSArrayWithElements(elements);
+ result->set_length(Smi::FromInt(cursor));
+ return result;
+}
+
+
+void Isolate::CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object) {
if (capture_stack_trace_for_uncaught_exceptions_) {
// Capture stack trace for a detailed exception message.
Handle<String> key = factory()->hidden_stack_trace_symbol();
@@ -910,15 +1000,28 @@
Failure* Isolate::StackOverflow() {
HandleScope scope;
+ // At this point we cannot create an Error object using its javascript
+ // constructor. Instead, we copy the pre-constructed boilerplate and
+ // attach the stack trace as a hidden property.
Handle<String> key = factory()->stack_overflow_symbol();
Handle<JSObject> boilerplate =
Handle<JSObject>::cast(GetProperty(js_builtins_object(), key));
- Handle<Object> exception = Copy(boilerplate);
- // TODO(1240995): To avoid having to call JavaScript code to compute
- // the message for stack overflow exceptions which is very likely to
- // double fault with another stack overflow exception, we use a
- // precomputed message.
+ Handle<JSObject> exception = Copy(boilerplate);
DoThrow(*exception, NULL);
+
+ // Get stack trace limit.
+ Handle<Object> error = GetProperty(js_builtins_object(), "$Error");
+ if (!error->IsJSObject()) return Failure::Exception();
+ Handle<Object> stack_trace_limit =
+ GetProperty(Handle<JSObject>::cast(error), "stackTraceLimit");
+ if (!stack_trace_limit->IsNumber()) return Failure::Exception();
+ int limit = static_cast<int>(stack_trace_limit->Number());
+
+ Handle<JSArray> stack_trace = CaptureSimpleStackTrace(
+ exception, factory()->undefined_value(), limit);
+ JSObject::SetHiddenProperty(exception,
+ factory()->hidden_stack_trace_symbol(),
+ stack_trace);
return Failure::Exception();
}
@@ -1125,18 +1228,22 @@
stack_trace_for_uncaught_exceptions_options_);
}
}
- // Stringify custom error objects for the message object.
- if (exception_handle->IsJSObject() && !IsErrorObject(exception_handle)) {
+
+ Handle<Object> exception_arg = exception_handle;
+ // If the exception argument is a custom object, turn it into a string
+ // before throwing as uncaught exception. Note that the pending
+ // exception object to be set later must not be turned into a string.
+ if (exception_arg->IsJSObject() && !IsErrorObject(exception_arg)) {
bool failed = false;
- exception_handle = Execution::ToString(exception_handle, &failed);
+ exception_arg = Execution::ToDetailString(exception_arg, &failed);
if (failed) {
- exception_handle = factory()->LookupAsciiSymbol("exception");
+ exception_arg = factory()->LookupAsciiSymbol("exception");
}
}
Handle<Object> message_obj = MessageHandler::MakeMessageObject(
"uncaught_exception",
location,
- HandleVector<Object>(&exception_handle, 1),
+ HandleVector<Object>(&exception_arg, 1),
stack_trace,
stack_trace_object);
thread_local_top()->pending_message_obj_ = *message_obj;
diff --git a/src/isolate.h b/src/isolate.h
index 167b762..2faee75 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -716,7 +716,10 @@
int frame_limit,
StackTrace::StackTraceOptions options);
- void CaptureAndSetCurrentStackTraceFor(Handle<JSObject> error_object);
+ Handle<JSArray> CaptureSimpleStackTrace(Handle<JSObject> error_object,
+ Handle<Object> caller,
+ int limit);
+ void CaptureAndSetDetailedStackTrace(Handle<JSObject> error_object);
// Returns if the top context may access the given global object. If
// the result is false, the pending exception is guaranteed to be
@@ -1395,12 +1398,7 @@
bool HasOverflowed() const {
StackGuard* stack_guard = isolate_->stack_guard();
- // Stack has overflowed in C++ code only if stack pointer exceeds the C++
- // stack guard and the limits are not set to interrupt values.
- // TODO(214): Stack overflows are ignored if a interrupt is pending. This
- // code should probably always use the initial C++ limit.
- return (reinterpret_cast<uintptr_t>(this) < stack_guard->climit()) &&
- stack_guard->IsStackOverflow();
+ return (reinterpret_cast<uintptr_t>(this) < stack_guard->real_climit());
}
private:
Isolate* isolate_;
diff --git a/src/json-stringifier.h b/src/json-stringifier.h
index cdb724f..68dc82a 100644
--- a/src/json-stringifier.h
+++ b/src/json-stringifier.h
@@ -274,7 +274,8 @@
return Handle<Object>(value, isolate_);
}
case FIELD: {
- Object* value = lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
+ Object* value = lookup.holder()->FastPropertyAt(
+ lookup.GetFieldIndex().field_index());
ASSERT(!value->IsTheHole());
return Handle<Object>(value, isolate_);
}
diff --git a/src/messages.js b/src/messages.js
index f04bed9..3d6c8ce 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -190,6 +190,7 @@
if (IS_BOOLEAN(obj)) return x ? 'true' : 'false';
if (IS_UNDEFINED(obj)) return 'undefined';
if (IS_NULL(obj)) return 'null';
+ if (IS_FUNCTION(obj)) return %_CallFunction(obj, FunctionToString);
if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) {
var constructor = obj.constructor;
if (typeof constructor == "function") {
@@ -755,29 +756,6 @@
// ----------------------------------------------------------------------------
// Error implementation
-// Defines accessors for a property that is calculated the first time
-// the property is read.
-function DefineOneShotAccessor(obj, name, fun) {
- // Note that the accessors consistently operate on 'obj', not 'this'.
- // Since the object may occur in someone else's prototype chain we
- // can't rely on 'this' being the same as 'obj'.
- var value;
- var value_factory = fun;
- var getter = function() {
- if (value_factory == null) {
- return value;
- }
- value = value_factory(obj);
- value_factory = null;
- return value;
- };
- var setter = function(v) {
- value_factory = null;
- value = v;
- };
- %DefineOrRedefineAccessorProperty(obj, name, getter, setter, DONT_ENUM);
-}
-
function CallSite(receiver, fun, pos) {
this.receiver = receiver;
this.fun = fun;
@@ -1112,9 +1090,21 @@
var raw_stack = %CollectStackTrace(obj,
cons_opt ? cons_opt : captureStackTrace,
stackTraceLimit);
- DefineOneShotAccessor(obj, 'stack', function (obj) {
- return FormatRawStackTrace(obj, raw_stack);
- });
+ // Note that 'obj' and 'this' maybe different when called on objects that
+ // have the error object on its prototype chain. The getter replaces itself
+ // with a data property as soon as the stack trace has been formatted.
+ var getter = function() {
+ var value = FormatRawStackTrace(obj, raw_stack);
+ %DefineOrRedefineDataProperty(obj, 'stack', value, NONE);
+ return value;
+ };
+ // The 'stack' property of the receiver is set as data property. If
+ // the receiver is the same as holder, this accessor pair is replaced.
+ var setter = function(v) {
+ %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
+ };
+
+ %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM);
}
@@ -1249,4 +1239,37 @@
// Boilerplate for exceptions for stack overflows. Used from
// Isolate::StackOverflow().
-var kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);
+function SetUpStackOverflowBoilerplate() {
+ var boilerplate = MakeRangeError('stack_overflow', []);
+
+ // The raw stack trace is stored as hidden property of the copy of this
+ // boilerplate error object. Note that the receiver 'this' may not be that
+ // error object copy, but can be found on the prototype chain of 'this'.
+ // When the stack trace is formatted, this accessor property is replaced by
+ // a data property.
+ function getter() {
+ var holder = this;
+ while (!IS_ERROR(holder)) {
+ holder = %GetPrototype(holder);
+ if (holder == null) return MakeSyntaxError('illegal_access', []);
+ }
+ var raw_stack = %GetOverflowedRawStackTrace(holder);
+ var result = IS_ARRAY(raw_stack) ? FormatRawStackTrace(holder, raw_stack)
+ : void 0;
+ %DefineOrRedefineDataProperty(holder, 'stack', result, NONE);
+ return result;
+ }
+
+ // The 'stack' property of the receiver is set as data property. If
+ // the receiver is the same as holder, this accessor pair is replaced.
+ function setter(v) {
+ %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
+ }
+
+ %DefineOrRedefineAccessorProperty(
+ boilerplate, 'stack', getter, setter, DONT_ENUM);
+
+ return boilerplate;
+}
+
+var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate();
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index bd15775..22e6174 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -314,18 +314,23 @@
Register dst,
Register src,
Handle<JSObject> holder,
- int index) {
- // Adjust for the number of properties stored in the holder.
- index -= holder->map()->inobject_properties();
- if (index < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (index * kPointerSize);
+ PropertyIndex index) {
+ if (index.is_header_index()) {
+ int offset = index.header_index() * kPointerSize;
__ lw(dst, FieldMemOperand(src, offset));
} else {
- // Calculate the offset into the properties array.
- int offset = index * kPointerSize + FixedArray::kHeaderSize;
- __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
- __ lw(dst, FieldMemOperand(dst, offset));
+ // Adjust for the number of properties stored in the holder.
+ int slot = index.field_index() - holder->map()->inobject_properties();
+ if (slot < 0) {
+ // Get the property straight out of the holder.
+ int offset = holder->map()->instance_size() + (slot * kPointerSize);
+ __ lw(dst, FieldMemOperand(src, offset));
+ } else {
+ // Calculate the offset into the properties array.
+ int offset = slot * kPointerSize + FixedArray::kHeaderSize;
+ __ lw(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
+ __ lw(dst, FieldMemOperand(dst, offset));
+ }
}
}
@@ -1200,7 +1205,7 @@
Register scratch1,
Register scratch2,
Register scratch3,
- int index,
+ PropertyIndex index,
Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
diff --git a/src/objects-inl.h b/src/objects-inl.h
index d5815f2..ab9ce1a 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -134,6 +134,14 @@
}
+// External objects are not extensible, so the map check is enough.
+bool Object::IsExternal() {
+ return Object::IsHeapObject() &&
+ HeapObject::cast(this)->map() ==
+ HeapObject::cast(this)->GetHeap()->external_map();
+}
+
+
bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
// There is a constraint on the object; check.
if (!this->IsJSObject()) return false;
diff --git a/src/objects.cc b/src/objects.cc
index fa5bfed..f8d080d 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -641,7 +641,8 @@
ASSERT(!value->IsTheHole() || result->IsReadOnly());
return value->IsTheHole() ? heap->undefined_value() : value;
case FIELD:
- value = result->holder()->FastPropertyAt(result->GetFieldIndex());
+ value = result->holder()->FastPropertyAt(
+ result->GetFieldIndex().field_index());
ASSERT(!value->IsTheHole() || result->IsReadOnly());
return value->IsTheHole() ? heap->undefined_value() : value;
case CONSTANT_FUNCTION:
@@ -2436,7 +2437,7 @@
// occur as fields.
if (result->IsField() &&
result->IsReadOnly() &&
- FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
+ FastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) {
result->DisallowCaching();
}
return;
@@ -2929,7 +2930,8 @@
result = self->SetNormalizedProperty(lookup, *value);
break;
case FIELD:
- result = self->FastPropertyAtPut(lookup->GetFieldIndex(), *value);
+ result = self->FastPropertyAtPut(
+ lookup->GetFieldIndex().field_index(), *value);
break;
case CONSTANT_FUNCTION:
// Only replace the function if necessary.
@@ -3095,7 +3097,8 @@
break;
}
case FIELD:
- result = self->FastPropertyAtPut(lookup.GetFieldIndex(), *value);
+ result = self->FastPropertyAtPut(
+ lookup.GetFieldIndex().field_index(), *value);
break;
case CONSTANT_FUNCTION:
// Only replace the function if necessary.
diff --git a/src/objects.h b/src/objects.h
index c86c0b2..3dc6188 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -907,6 +907,7 @@
#undef IS_TYPE_FUNCTION_DECL
inline bool IsFixedArrayBase();
+ inline bool IsExternal();
// Returns true if this object is an instance of the specified
// function template.
@@ -2451,6 +2452,8 @@
Object* value);
private:
+ STATIC_CHECK(kHeaderSize == Internals::kFixedArrayHeaderSize);
+
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedArray);
};
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 9839edf..25ce2ba 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -1988,7 +1988,7 @@
"(context func. result caches)");
TagObject(context->normalized_map_cache(), "(context norm. map cache)");
TagObject(context->runtime_context(), "(runtime context)");
- TagObject(context->data(), "(context data)");
+ TagObject(context->embedder_data(), "(context data)");
NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD);
#undef EXTRACT_CONTEXT_FIELD
for (int i = Context::FIRST_WEAK_SLOT;
diff --git a/src/property.cc b/src/property.cc
index 05342ee..cbf2fc8 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -63,7 +63,7 @@
break;
case FIELD:
PrintF(out, " -type = field\n");
- PrintF(out, " -index = %d", GetFieldIndex());
+ PrintF(out, " -index = %d", GetFieldIndex().field_index());
PrintF(out, "\n");
break;
case CALLBACKS:
diff --git a/src/property.h b/src/property.h
index 3faa28b..c41c6dc 100644
--- a/src/property.h
+++ b/src/property.h
@@ -132,6 +132,44 @@
};
+// Holds a property index value distinguishing if it is a field index or an
+// index inside the object header.
+class PropertyIndex {
+ public:
+ static PropertyIndex NewFieldIndex(int index) {
+ return PropertyIndex(index, false);
+ }
+ static PropertyIndex NewHeaderIndex(int index) {
+ return PropertyIndex(index, true);
+ }
+
+ bool is_field_index() { return (index_ & kHeaderIndexBit) == 0; }
+ bool is_header_index() { return (index_ & kHeaderIndexBit) != 0; }
+
+ int field_index() {
+ ASSERT(is_field_index());
+ return value();
+ }
+ int header_index() {
+ ASSERT(is_header_index());
+ return value();
+ }
+
+ private:
+ static const int kHeaderIndexBit = 1 << 31;
+ static const int kIndexMask = ~kHeaderIndexBit;
+
+ int value() { return index_ & kIndexMask; }
+
+ PropertyIndex(int index, bool is_header_based)
+ : index_(index | (is_header_based ? kHeaderIndexBit : 0)) {
+ ASSERT(index <= kIndexMask);
+ }
+
+ int index_;
+};
+
+
class LookupResult BASE_EMBEDDED {
public:
explicit LookupResult(Isolate* isolate)
@@ -278,7 +316,7 @@
Object* GetLazyValue() {
switch (type()) {
case FIELD:
- return holder()->FastPropertyAt(GetFieldIndex());
+ return holder()->FastPropertyAt(GetFieldIndex().field_index());
case NORMAL: {
Object* value;
value = holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
@@ -334,10 +372,11 @@
return number_;
}
- int GetFieldIndex() {
+ PropertyIndex GetFieldIndex() {
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
ASSERT(IsField());
- return Descriptor::IndexFromValue(GetValue());
+ return PropertyIndex::NewFieldIndex(
+ Descriptor::IndexFromValue(GetValue()));
}
int GetLocalFieldIndexFromMap(Map* map) {
diff --git a/src/runtime.cc b/src/runtime.cc
index 11ba4c8..de74f2c 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -1679,7 +1679,7 @@
// Strict mode handling not needed (const is disallowed in strict mode).
if (lookup.IsField()) {
FixedArray* properties = global->properties();
- int index = lookup.GetFieldIndex();
+ int index = lookup.GetFieldIndex().field_index();
if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
properties->set(index, *value);
}
@@ -1769,7 +1769,7 @@
if (lookup.IsField()) {
FixedArray* properties = object->properties();
- int index = lookup.GetFieldIndex();
+ int index = lookup.GetFieldIndex().field_index();
if (properties->get(index)->IsTheHole()) {
properties->set(index, *value);
}
@@ -4076,7 +4076,7 @@
LookupResult result(isolate);
receiver->LocalLookup(key, &result);
if (result.IsField()) {
- int offset = result.GetFieldIndex();
+ int offset = result.GetFieldIndex().field_index();
keyed_lookup_cache->Update(receiver_map, key, offset);
return receiver->FastPropertyAt(offset);
}
@@ -4250,7 +4250,8 @@
case NORMAL:
return lookup.holder()->GetNormalizedProperty(&lookup);
case FIELD:
- return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
+ return lookup.holder()->FastPropertyAt(
+ lookup.GetFieldIndex().field_index());
case CONSTANT_FUNCTION:
return lookup.GetConstantFunction();
case CALLBACKS:
@@ -10010,8 +10011,8 @@
return value;
case FIELD:
value =
- JSObject::cast(
- result->holder())->FastPropertyAt(result->GetFieldIndex());
+ JSObject::cast(result->holder())->FastPropertyAt(
+ result->GetFieldIndex().field_index());
if (value->IsTheHole()) {
return heap->undefined_value();
}
@@ -12903,47 +12904,6 @@
}
-// Determines whether the given stack frame should be displayed in
-// a stack trace. The caller is the error constructor that asked
-// for the stack trace to be collected. The first time a construct
-// call to this function is encountered it is skipped. The seen_caller
-// in/out parameter is used to remember if the caller has been seen
-// yet.
-static bool ShowFrameInStackTrace(StackFrame* raw_frame,
- Object* caller,
- bool* seen_caller) {
- // Only display JS frames.
- if (!raw_frame->is_java_script()) {
- return false;
- }
- JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
- Object* raw_fun = frame->function();
- // Not sure when this can happen but skip it just in case.
- if (!raw_fun->IsJSFunction()) {
- return false;
- }
- if ((raw_fun == caller) && !(*seen_caller)) {
- *seen_caller = true;
- return false;
- }
- // Skip all frames until we've seen the caller.
- if (!(*seen_caller)) return false;
- // Also, skip non-visible built-in functions and any call with the builtins
- // object as receiver, so as to not reveal either the builtins object or
- // an internal function.
- // The --builtins-in-stack-traces command line flag allows including
- // internal call sites in the stack trace for debugging purposes.
- if (!FLAG_builtins_in_stack_traces) {
- JSFunction* fun = JSFunction::cast(raw_fun);
- if (frame->receiver()->IsJSBuiltinsObject() ||
- (fun->IsBuiltin() && !fun->shared()->native())) {
- return false;
- }
- }
- return true;
-}
-
-
// Collect the raw data for a stack trace. Returns an array of 4
// element segments each containing a receiver, function, code and
// native code offset.
@@ -12954,57 +12914,23 @@
CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
HandleScope scope(isolate);
- Factory* factory = isolate->factory();
+ // Optionally capture a more detailed stack trace for the message.
+ isolate->CaptureAndSetDetailedStackTrace(error_object);
+ // Capture a simple stack trace for the stack property.
+ return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
+}
- limit = Max(limit, 0); // Ensure that limit is not negative.
- int initial_size = Min(limit, 10);
- Handle<FixedArray> elements =
- factory->NewFixedArrayWithHoles(initial_size * 4);
- StackFrameIterator iter(isolate);
- // If the caller parameter is a function we skip frames until we're
- // under it before starting to collect.
- bool seen_caller = !caller->IsJSFunction();
- int cursor = 0;
- int frames_seen = 0;
- while (!iter.done() && frames_seen < limit) {
- StackFrame* raw_frame = iter.frame();
- if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
- frames_seen++;
- JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
- // Set initial size to the maximum inlining level + 1 for the outermost
- // function.
- List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
- frame->Summarize(&frames);
- for (int i = frames.length() - 1; i >= 0; i--) {
- if (cursor + 4 > elements->length()) {
- int new_capacity = JSObject::NewElementsCapacity(elements->length());
- Handle<FixedArray> new_elements =
- factory->NewFixedArrayWithHoles(new_capacity);
- for (int i = 0; i < cursor; i++) {
- new_elements->set(i, elements->get(i));
- }
- elements = new_elements;
- }
- ASSERT(cursor + 4 <= elements->length());
-
- Handle<Object> recv = frames[i].receiver();
- Handle<JSFunction> fun = frames[i].function();
- Handle<Code> code = frames[i].code();
- Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
- elements->set(cursor++, *recv);
- elements->set(cursor++, *fun);
- elements->set(cursor++, *code);
- elements->set(cursor++, *offset);
- }
- }
- iter.Advance();
- }
- Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
- // Capture and attach a more detailed stack trace if necessary.
- isolate->CaptureAndSetCurrentStackTraceFor(error_object);
- result->set_length(Smi::FromInt(cursor));
- return *result;
+// Retrieve the raw stack trace collected on stack overflow and delete
+// it since it is used only once to avoid keeping it alive.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOverflowedRawStackTrace) {
+ ASSERT_EQ(args.length(), 1);
+ CONVERT_ARG_CHECKED(JSObject, error_object, 0);
+ String* key = isolate->heap()->hidden_stack_trace_symbol();
+ Object* result = error_object->GetHiddenProperty(key);
+ RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
+ error_object->DeleteHiddenProperty(key);
+ return result;
}
diff --git a/src/runtime.h b/src/runtime.h
index f63844c..caed34b 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -233,6 +233,7 @@
F(FunctionIsBuiltin, 1, 1) \
F(GetScript, 1, 1) \
F(CollectStackTrace, 3, 1) \
+ F(GetOverflowedRawStackTrace, 1, 1) \
F(GetV8Version, 0, 1) \
\
F(ClassOf, 1, 1) \
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 5eb0cba..fcb8a4e 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -136,7 +136,7 @@
Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- int field_index) {
+ PropertyIndex field_index) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::FIELD);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
@@ -261,7 +261,7 @@
Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- int field_index) {
+ PropertyIndex field_index) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::FIELD);
@@ -632,7 +632,7 @@
Handle<String> name,
Handle<Object> object,
Handle<JSObject> holder,
- int index) {
+ PropertyIndex index) {
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 005c537..f858e47 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -83,7 +83,7 @@
Handle<Code> ComputeLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- int field_index);
+ PropertyIndex field_index);
Handle<Code> ComputeLoadCallback(Handle<String> name,
Handle<JSObject> receiver,
@@ -117,7 +117,7 @@
Handle<Code> ComputeKeyedLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- int field_index);
+ PropertyIndex field_index);
Handle<Code> ComputeKeyedLoadCallback(Handle<String> name,
Handle<JSObject> receiver,
@@ -193,7 +193,7 @@
Handle<String> name,
Handle<Object> object,
Handle<JSObject> holder,
- int index);
+ PropertyIndex index);
Handle<Code> ComputeCallConstant(int argc,
Code::Kind,
@@ -453,7 +453,7 @@
Register dst,
Register src,
Handle<JSObject> holder,
- int index);
+ PropertyIndex index);
static void GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
@@ -540,7 +540,7 @@
Register scratch1,
Register scratch2,
Register scratch3,
- int index,
+ PropertyIndex index,
Handle<String> name,
Label* miss);
@@ -611,7 +611,7 @@
Handle<Code> CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name);
Handle<Code> CompileLoadCallback(Handle<String> name,
@@ -654,7 +654,7 @@
Handle<Code> CompileLoadField(Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> holder,
- int index);
+ PropertyIndex index);
Handle<Code> CompileLoadCallback(Handle<String> name,
Handle<JSObject> object,
@@ -803,7 +803,7 @@
Handle<Code> CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name);
Handle<Code> CompileCallConstant(Handle<Object> object,
diff --git a/src/version.cc b/src/version.cc
index 3132b5e..b61775b 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 15
-#define BUILD_NUMBER 2
+#define BUILD_NUMBER 3
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 4596aca..2bcf943 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2624,30 +2624,24 @@
}
-template <class T>
-inline void LCodeGen::PrepareKeyForKeyedOp(T* hydrogen_instr, LOperand* key) {
- if (ArrayOpClobbersKey<T>(hydrogen_instr)) {
+void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
+ ElementsKind elements_kind = instr->elements_kind();
+ LOperand* key = instr->key();
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
// Even though the HLoad/StoreKeyed (in this case) instructions force
// the input representation for the key to be an integer, the input
// gets replaced during bound check elimination with the index argument
// to the bounds check, which can be tagged, so that case must be
// handled here, too.
- Register key_reg = ToRegister(key);
- if (hydrogen_instr->key()->representation().IsTagged()) {
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
__ SmiToInteger64(key_reg, key_reg);
- } else if (hydrogen_instr->IsDehoisted()) {
+ } else if (instr->hydrogen()->IsDehoisted()) {
// Sign extend key because it could be a 32 bit negative value
// and the dehoisted address computation happens in 64 bits
__ movsxlq(key_reg, key_reg);
}
}
-}
-
-
-void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
- ElementsKind elements_kind = instr->elements_kind();
- LOperand* key = instr->key();
- PrepareKeyForKeyedOp(instr->hydrogen(), key);
Operand operand(BuildFastArrayOperand(
instr->elements(),
key,
@@ -2707,7 +2701,21 @@
void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
XMMRegister result(ToDoubleRegister(instr->result()));
LOperand* key = instr->key();
- PrepareKeyForKeyedOp<HLoadKeyed>(instr->hydrogen(), key);
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ // Even though the HLoad/StoreKeyed instructions force the input
+ // representation for the key to be an integer, the input gets replaced
+ // during bound check elimination with the index argument to the bounds
+ // check, which can be tagged, so that case must be handled here, too.
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
+ }
+
if (instr->hydrogen()->RequiresHoleCheck()) {
int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
sizeof(kHoleNanLower32);
@@ -2734,7 +2742,21 @@
void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
Register result = ToRegister(instr->result());
LOperand* key = instr->key();
- PrepareKeyForKeyedOp<HLoadKeyed>(instr->hydrogen(), key);
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ // Even though the HLoad/StoreKeyedFastElement instructions force
+ // the input representation for the key to be an integer, the input
+ // gets replaced during bound check elimination with the index
+ // argument to the bounds check, which can be tagged, so that
+ // case must be handled here, too.
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
+ }
// Load the result.
__ movq(result,
@@ -3729,7 +3751,21 @@
void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
ElementsKind elements_kind = instr->elements_kind();
LOperand* key = instr->key();
- PrepareKeyForKeyedOp<HStoreKeyed>(instr->hydrogen(), key);
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ // Even though the HLoad/StoreKeyedFastElement instructions force
+ // the input representation for the key to be an integer, the input
+ // gets replaced during bound check elimination with the index
+ // argument to the bounds check, which can be tagged, so that case
+ // must be handled here, too.
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
+ }
Operand operand(BuildFastArrayOperand(
instr->elements(),
key,
@@ -3779,7 +3815,22 @@
void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
XMMRegister value = ToDoubleRegister(instr->value());
LOperand* key = instr->key();
- PrepareKeyForKeyedOp<HStoreKeyed>(instr->hydrogen(), key);
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ // Even though the HLoad/StoreKeyedFastElement instructions force
+ // the input representation for the key to be an integer, the
+ // input gets replaced during bound check elimination with the index
+ // argument to the bounds check, which can be tagged, so that case
+ // must be handled here, too.
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
+ }
+
if (instr->NeedsCanonicalization()) {
Label have_value;
@@ -3808,7 +3859,21 @@
Register value = ToRegister(instr->value());
Register elements = ToRegister(instr->elements());
LOperand* key = instr->key();
- PrepareKeyForKeyedOp<HStoreKeyed>(instr->hydrogen(), key);
+ if (!key->IsConstantOperand()) {
+ Register key_reg = ToRegister(key);
+ // Even though the HLoad/StoreKeyedFastElement instructions force
+ // the input representation for the key to be an integer, the
+ // input gets replaced during bound check elimination with the index
+ // argument to the bounds check, which can be tagged, so that case
+ // must be handled here, too.
+ if (instr->hydrogen()->key()->representation().IsTagged()) {
+ __ SmiToInteger64(key_reg, key_reg);
+ } else if (instr->hydrogen()->IsDehoisted()) {
+ // Sign extend key because it could be a 32 bit negative value
+ // and the dehoisted address computation happens in 64 bits
+ __ movsxlq(key_reg, key_reg);
+ }
+ }
Operand operand =
BuildFastArrayOperand(instr->elements(),
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 0f8a62a..e068f14 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -341,8 +341,6 @@
void DoStoreKeyedExternalArray(LStoreKeyed* instr);
void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
void DoStoreKeyedFixedArray(LStoreKeyed* instr);
- template <class T>
- void PrepareKeyForKeyedOp(T* hydrogen_instr, LOperand* key);
Zone* zone_;
LPlatformChunk* const chunk_;
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index c6004e5..a874a24 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1844,15 +1844,16 @@
ASSERT(instr->key()->representation().IsInteger32() ||
instr->key()->representation().IsTagged());
ElementsKind elements_kind = instr->elements_kind();
- bool clobbers_key = ArrayOpClobbersKey<HLoadKeyed>(instr);
+ bool clobbers_key = instr->key()->representation().IsTagged();
LOperand* key = clobbers_key
? UseTempRegister(instr->key())
: UseRegisterOrConstantAtStart(instr->key());
- LOperand* elements = UseRegisterAtStart(instr->elements());
- LLoadKeyed* result = new(zone()) LLoadKeyed(elements, key);
+ LLoadKeyed* result = NULL;
-#ifdef DEBUG
- if (instr->is_external()) {
+ if (!instr->is_external()) {
+ LOperand* obj = UseRegisterAtStart(instr->elements());
+ result = new(zone()) LLoadKeyed(obj, key);
+ } else {
ASSERT(
(instr->representation().IsInteger32() &&
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
@@ -1860,8 +1861,9 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
+ LOperand* external_pointer = UseRegister(instr->elements());
+ result = new(zone()) LLoadKeyed(external_pointer, key);
}
-#endif
DefineAsRegister(result);
bool can_deoptimize = instr->RequiresHoleCheck() ||
@@ -1882,21 +1884,33 @@
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
+ ElementsKind elements_kind = instr->elements_kind();
bool needs_write_barrier = instr->NeedsWriteBarrier();
- bool clobbers_key = ArrayOpClobbersKey<HStoreKeyed>(instr);
+ bool clobbers_key = instr->key()->representation().IsTagged();
LOperand* key = (clobbers_key || needs_write_barrier)
? UseTempRegister(instr->key())
: UseRegisterOrConstantAtStart(instr->key());
- LOperand* val = needs_write_barrier
+ bool val_is_temp_register =
+ elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
+ elements_kind == EXTERNAL_FLOAT_ELEMENTS;
+ LOperand* val = (needs_write_barrier || val_is_temp_register)
? UseTempRegister(instr->value())
: UseRegisterAtStart(instr->value());
- LOperand* elements = UseRegisterAtStart(instr->elements());
+ LStoreKeyed* result = NULL;
-#ifdef DEBUG
if (!instr->is_external()) {
ASSERT(instr->elements()->representation().IsTagged());
+
+ LOperand* object = NULL;
+ if (instr->value()->representation().IsDouble()) {
+ object = UseRegisterAtStart(instr->elements());
+ } else {
+ ASSERT(instr->value()->representation().IsTagged());
+ object = UseTempRegister(instr->elements());
+ }
+
+ result = new(zone()) LStoreKeyed(object, key, val);
} else {
- ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(instr->value()->representation().IsInteger32() &&
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
@@ -1905,10 +1919,11 @@
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->elements()->representation().IsExternal());
- }
-#endif
- LStoreKeyed* result = new(zone()) LStoreKeyed(elements, key, val);
+ LOperand* external_pointer = UseRegister(instr->elements());
+ result = new(zone()) LStoreKeyed(external_pointer, key, val);
+ }
+
ASSERT(result != NULL);
return result;
}
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 5439028..79ce968 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -1371,14 +1371,6 @@
};
-template <class T>
-inline static bool ArrayOpClobbersKey(T *value) {
- CHECK(value->IsLoadKeyed() || value->IsStoreKeyed());
- return !value->IsConstant() && (value->key()->representation().IsTagged()
- || value->IsDehoisted());
-}
-
-
class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedGeneric(LOperand* obj, LOperand* key) {
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index b120efb..3495e8d 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -350,18 +350,23 @@
Register dst,
Register src,
Handle<JSObject> holder,
- int index) {
- // Adjust for the number of properties stored in the holder.
- index -= holder->map()->inobject_properties();
- if (index < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (index * kPointerSize);
+ PropertyIndex index) {
+ if (index.is_header_index()) {
+ int offset = index.header_index() * kPointerSize;
__ movq(dst, FieldOperand(src, offset));
} else {
- // Calculate the offset into the properties array.
- int offset = index * kPointerSize + FixedArray::kHeaderSize;
- __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
- __ movq(dst, FieldOperand(dst, offset));
+ // Adjust for the number of properties stored in the holder.
+ int slot = index.field_index() - holder->map()->inobject_properties();
+ if (slot < 0) {
+ // Get the property straight out of the holder.
+ int offset = holder->map()->instance_size() + (slot * kPointerSize);
+ __ movq(dst, FieldOperand(src, offset));
+ } else {
+ // Calculate the offset into the properties array.
+ int offset = slot * kPointerSize + FixedArray::kHeaderSize;
+ __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ __ movq(dst, FieldOperand(dst, offset));
+ }
}
}
@@ -1013,7 +1018,7 @@
Register scratch1,
Register scratch2,
Register scratch3,
- int index,
+ PropertyIndex index,
Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
@@ -1388,7 +1393,7 @@
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name) {
// ----------- S t a t e -------------
// rcx : function name
@@ -2780,7 +2785,7 @@
Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
- int index,
+ PropertyIndex index,
Handle<String> name) {
// ----------- S t a t e -------------
// -- rax : receiver
@@ -2973,7 +2978,7 @@
Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- int index) {
+ PropertyIndex index) {
// ----------- S t a t e -------------
// -- rax : key
// -- rdx : receiver
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 41eb68f..206e95a 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -25,6 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// We want to test our deprecated API entries, too.
+#define V8_DISABLE_DEPRECATIONS 1
+
#include <limits.h>
#ifndef WIN32
@@ -2056,6 +2059,99 @@
}
+static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
+ void* value) {
+ CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
+ obj->SetPointerInInternalField(0, value);
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CHECK_EQ(value, obj->GetPointerFromInternalField(0));
+}
+
+
+THREADED_TEST(InternalFieldsAlignedPointers) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+ Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
+ instance_templ->SetInternalFieldCount(1);
+ Local<v8::Object> obj = templ->GetFunction()->NewInstance();
+ CHECK_EQ(1, obj->InternalFieldCount());
+
+ CheckAlignedPointerInInternalField(obj, NULL);
+
+ int* heap_allocated = new int[100];
+ CheckAlignedPointerInInternalField(obj, heap_allocated);
+ delete[] heap_allocated;
+
+ int stack_allocated[100];
+ CheckAlignedPointerInInternalField(obj, stack_allocated);
+
+ void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
+ CheckAlignedPointerInInternalField(obj, huge);
+}
+
+
+static void CheckAlignedPointerInEmbedderData(LocalContext* env,
+ int index,
+ void* value) {
+ CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
+ (*env)->SetAlignedPointerInEmbedderData(index, value);
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+ CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
+}
+
+
+static void* AlignedTestPointer(int i) {
+ return reinterpret_cast<void*>(i * 1234);
+}
+
+
+THREADED_TEST(EmbedderDataAlignedPointers) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CheckAlignedPointerInEmbedderData(&env, 0, NULL);
+
+ int* heap_allocated = new int[100];
+ CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
+ delete[] heap_allocated;
+
+ int stack_allocated[100];
+ CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
+
+ void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
+ CheckAlignedPointerInEmbedderData(&env, 3, huge);
+
+ // Test growing of the embedder data's backing store.
+ for (int i = 0; i < 100; i++) {
+ env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
+ }
+ HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
+ for (int i = 0; i < 100; i++) {
+ CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
+ }
+}
+
+
+static void CheckEmbedderData(LocalContext* env,
+ int index,
+ v8::Handle<Value> data) {
+ (*env)->SetEmbedderData(index, data);
+ CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
+}
+
+THREADED_TEST(EmbedderData) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
+ CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
+ CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
+ CheckEmbedderData(&env, 0, v8::Boolean::New(true));
+}
+
+
THREADED_TEST(IdentityHash) {
v8::HandleScope scope;
LocalContext env;
@@ -2554,6 +2650,18 @@
}
+TEST(TryCatchCustomException) {
+ v8::HandleScope scope;
+ LocalContext env;
+ v8::TryCatch try_catch;
+ CompileRun("function CustomError() { this.a = 'b'; }"
+ "(function f() { throw new CustomError(); })();");
+ CHECK(try_catch.HasCaught());
+ CHECK(try_catch.Exception()->ToObject()->
+ Get(v8_str("a"))->Equals(v8_str("b")));
+}
+
+
bool message_received;
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index f2253e3..a719a62 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -27,6 +27,9 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
+// TODO(svenpanne): Do not use Context::GetData and Context::SetData.
+#define V8_DISABLE_DEPRECATIONS 1
+
#include <stdlib.h>
#include "v8.h"
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index 6fc6012..e398cbb 100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -190,7 +190,8 @@
DeclarationContext* DeclarationContext::GetInstance(const AccessorInfo& info) {
- return static_cast<DeclarationContext*>(External::Unwrap(info.Data()));
+ void* value = External::Cast(*info.Data())->Value();
+ return static_cast<DeclarationContext*>(value);
}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 2bb3af6..27fa4b1 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -2410,19 +2410,13 @@
};
-TEST(ReleaseStackTraceData) {
+void ReleaseStackTraceDataTest(const char* source) {
// Test that the data retained by the Error.stack accessor is released
// after the first time the accessor is fired. We use external string
// to check whether the data is being released since the external string
// resource's callback is fired when the external string is GC'ed.
InitializeVM();
v8::HandleScope scope;
- static const char* source = "var error = 1; "
- "try { "
- " throw new Error(); "
- "} catch (e) { "
- " error = e; "
- "} ";
SourceResource* resource = new SourceResource(i::StrDup(source));
{
v8::HandleScope scope;
@@ -2434,15 +2428,32 @@
// External source is being retained by the stack trace.
CHECK(!resource->IsDisposed());
- CompileRun("error.stack; error.stack;");
+ CompileRun("error.stack;");
HEAP->CollectAllAvailableGarbage();
// External source has been released.
CHECK(resource->IsDisposed());
-
delete resource;
}
+TEST(ReleaseStackTraceData) {
+ static const char* source1 = "var error = null; "
+ /* Normal Error */ "try { "
+ " throw new Error(); "
+ "} catch (e) { "
+ " error = e; "
+ "} ";
+ static const char* source2 = "var error = null; "
+ /* Stack overflow */ "try { "
+ " (function f() { f(); })(); "
+ "} catch (e) { "
+ " error = e; "
+ "} ";
+ ReleaseStackTraceDataTest(source1);
+ ReleaseStackTraceDataTest(source2);
+}
+
+
TEST(Regression144230) {
InitializeVM();
v8::HandleScope scope;
diff --git a/test/mjsunit/json-recursive.js b/test/mjsunit/json-parser-recursive.js
similarity index 73%
copy from test/mjsunit/json-recursive.js
copy to test/mjsunit/json-parser-recursive.js
index 7a8c547..1e00c83 100644
--- a/test/mjsunit/json-recursive.js
+++ b/test/mjsunit/json-parser-recursive.js
@@ -25,34 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-var a = {};
-for (i = 0; i < 10000; i++) {
- var current = {};
- current.a = a;
- a = current;
-}
-
-function rec(a,b,c,d,e,f,g,h,i,j,k,l,m,n) {
- JSON.stringify(a);
- rec(a,b,c,d,e,f,g,h,i,j,k,l,m,n);
-}
-
-assertThrows(function() { rec(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4) },
- RangeError);
-
-
-var depth = 10000;
-var deepArray = [];
-for (var i = 0; i < depth; i++) deepArray = [deepArray];
-assertThrows(function() { JSON.stringify(deepArray); }, RangeError);
-
-
-var deepObject = {};
-for (var i = 0; i < depth; i++) deepObject = { next: deepObject };
-assertThrows(function() { JSON.stringify(deepObject); }, RangeError);
-
-
var str = "[1]";
for (var i = 0; i < 100000; i++) {
str = "[1," + str + "]";
diff --git a/test/mjsunit/json-recursive.js b/test/mjsunit/json-stringify-recursive.js
similarity index 93%
rename from test/mjsunit/json-recursive.js
rename to test/mjsunit/json-stringify-recursive.js
index 7a8c547..31aa002 100644
--- a/test/mjsunit/json-recursive.js
+++ b/test/mjsunit/json-stringify-recursive.js
@@ -25,7 +25,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
var a = {};
for (i = 0; i < 10000; i++) {
var current = {};
@@ -51,11 +50,3 @@
var deepObject = {};
for (var i = 0; i < depth; i++) deepObject = { next: deepObject };
assertThrows(function() { JSON.stringify(deepObject); }, RangeError);
-
-
-var str = "[1]";
-for (var i = 0; i < 100000; i++) {
- str = "[1," + str + "]";
-}
-
-assertThrows(function() { JSON.parse(str); }, RangeError);
diff --git a/test/mjsunit/stack-traces-overflow.js b/test/mjsunit/stack-traces-overflow.js
new file mode 100644
index 0000000..7722e93
--- /dev/null
+++ b/test/mjsunit/stack-traces-overflow.js
@@ -0,0 +1,122 @@
+// 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function rec1(a) { rec1(a+1); }
+function rec2(a) { rec3(a+1); }
+function rec3(a) { rec2(a+1); }
+
+// Test stack trace getter and setter.
+try {
+ rec1(0);
+} catch (e) {
+ assertTrue(e.stack.indexOf("rec1") > 0);
+ e.stack = "123";
+ assertEquals("123", e.stack);
+}
+
+// Test setter w/o calling the getter.
+try {
+ rec2(0);
+} catch (e) {
+ assertTrue(e.stack.indexOf("rec2") > 0);
+ assertTrue(e.stack.indexOf("rec3") > 0);
+ e.stack = "123";
+ assertEquals("123", e.stack);
+}
+
+// Test getter to make sure setter does not affect the boilerplate.
+try {
+ rec1(0);
+} catch (e) {
+ assertTrue(e.stack.indexOf("rec1") > 0);
+ assertInstanceof(e, RangeError);
+}
+
+
+// Check setting/getting stack property on the prototype chain.
+function testErrorPrototype(prototype) {
+ var object = {};
+ object.__proto__ = prototype;
+ object.stack = "123";
+ assertEquals("123", object.stack);
+ assertTrue("123" != prototype.stack);
+}
+
+try {
+ rec1(0);
+} catch (e) {
+ e.stack;
+ testErrorPrototype(e);
+}
+
+try {
+ rec1(0);
+} catch (e) {
+ testErrorPrototype(e);
+}
+
+try {
+ throw new Error();
+} catch (e) {
+ testErrorPrototype(e);
+}
+
+Error.stackTraceLimit = 3;
+try {
+ rec1(0);
+} catch (e) {
+ assertEquals(4, e.stack.split('\n').length);
+}
+
+Error.stackTraceLimit = 25.9;
+try {
+ rec1(0);
+} catch (e) {
+ assertEquals(26, e.stack.split('\n').length);
+}
+
+Error.stackTraceLimit = NaN;
+try {
+ rec1(0);
+} catch (e) {
+ assertEquals(1, e.stack.split('\n').length);
+}
+
+Error.stackTraceLimit = "not a number";
+try {
+ rec1(0);
+} catch (e) {
+ assertEquals(undefined, e.stack);
+}
+
+Error.stackTraceLimit = 3;
+Error = ""; // Overwrite Error in the global object.
+try {
+ rec1(0);
+} catch (e) {
+ assertEquals(4, e.stack.split('\n').length);
+}
diff --git a/tools/grokdump.py b/tools/grokdump.py
index 46ead5e..b51e4e0 100755
--- a/tools/grokdump.py
+++ b/tools/grokdump.py
@@ -863,80 +863,83 @@
# }
# printf("}\n");
KNOWN_MAPS = {
- 0x08081: (134, "ByteArrayMap"),
- 0x080a1: (128, "MetaMap"),
- 0x080c1: (130, "OddballMap"),
- 0x080e1: (163, "FixedArrayMap"),
- 0x08101: (68, "AsciiSymbolMap"),
- 0x08121: (132, "HeapNumberMap"),
- 0x08141: (135, "FreeSpaceMap"),
- 0x08161: (146, "OnePointerFillerMap"),
- 0x08181: (146, "TwoPointerFillerMap"),
- 0x081a1: (131, "GlobalPropertyCellMap"),
- 0x081c1: (164, "SharedFunctionInfoMap"),
- 0x081e1: (4, "AsciiStringMap"),
- 0x08201: (163, "GlobalContextMap"),
- 0x08221: (129, "CodeMap"),
- 0x08241: (163, "ScopeInfoMap"),
- 0x08261: (163, "FixedCOWArrayMap"),
- 0x08281: (145, "FixedDoubleArrayMap"),
- 0x082a1: (163, "HashTableMap"),
- 0x082c1: (0, "StringMap"),
- 0x082e1: (64, "SymbolMap"),
- 0x08301: (1, "ConsStringMap"),
- 0x08321: (5, "ConsAsciiStringMap"),
- 0x08341: (3, "SlicedStringMap"),
- 0x08361: (7, "SlicedAsciiStringMap"),
- 0x08381: (65, "ConsSymbolMap"),
- 0x083a1: (69, "ConsAsciiSymbolMap"),
- 0x083c1: (66, "ExternalSymbolMap"),
- 0x083e1: (74, "ExternalSymbolWithAsciiDataMap"),
- 0x08401: (70, "ExternalAsciiSymbolMap"),
- 0x08421: (2, "ExternalStringMap"),
- 0x08441: (10, "ExternalStringWithAsciiDataMap"),
- 0x08461: (6, "ExternalAsciiStringMap"),
- 0x08481: (82, "ShortExternalSymbolMap"),
- 0x084a1: (90, "ShortExternalSymbolWithAsciiDataMap"),
- 0x084c1: (86, "ShortExternalAsciiSymbolMap"),
- 0x084e1: (18, "ShortExternalStringMap"),
- 0x08501: (26, "ShortExternalStringWithAsciiDataMap"),
- 0x08521: (22, "ShortExternalAsciiStringMap"),
- 0x08541: (0, "UndetectableStringMap"),
- 0x08561: (4, "UndetectableAsciiStringMap"),
- 0x08581: (144, "ExternalPixelArrayMap"),
- 0x085a1: (136, "ExternalByteArrayMap"),
- 0x085c1: (137, "ExternalUnsignedByteArrayMap"),
- 0x085e1: (138, "ExternalShortArrayMap"),
- 0x08601: (139, "ExternalUnsignedShortArrayMap"),
- 0x08621: (140, "ExternalIntArrayMap"),
- 0x08641: (141, "ExternalUnsignedIntArrayMap"),
- 0x08661: (142, "ExternalFloatArrayMap"),
- 0x08681: (143, "ExternalDoubleArrayMap"),
- 0x086a1: (163, "NonStrictArgumentsElementsMap"),
- 0x086c1: (163, "FunctionContextMap"),
- 0x086e1: (163, "CatchContextMap"),
- 0x08701: (163, "WithContextMap"),
- 0x08721: (163, "BlockContextMap"),
- 0x08741: (163, "ModuleContextMap"),
- 0x08761: (165, "JSMessageObjectMap"),
- 0x08781: (133, "ForeignMap"),
- 0x087a1: (170, "NeanderMap"),
- 0x087c1: (158, "PolymorphicCodeCacheMap"),
- 0x087e1: (156, "ScriptMap"),
- 0x08801: (147, "AccessorInfoMap"),
- 0x08821: (148, "AccessorPairMap"),
- 0x08841: (149, "AccessCheckInfoMap"),
- 0x08861: (150, "InterceptorInfoMap"),
- 0x08881: (151, "CallHandlerInfoMap"),
- 0x088a1: (152, "FunctionTemplateInfoMap"),
- 0x088c1: (153, "ObjectTemplateInfoMap"),
- 0x088e1: (154, "SignatureInfoMap"),
- 0x08901: (155, "TypeSwitchInfoMap"),
- 0x08921: (157, "CodeCacheMap"),
- 0x08941: (159, "TypeFeedbackInfoMap"),
- 0x08961: (160, "AliasedArgumentsEntryMap"),
- 0x08981: (161, "DebugInfoMap"),
- 0x089a1: (162, "BreakPointInfoMap"),
+ 0x08081: (128, "MetaMap"),
+ 0x080a5: (163, "FixedArrayMap"),
+ 0x080c9: (130, "OddballMap"),
+ 0x080ed: (163, "FixedCOWArrayMap"),
+ 0x08111: (163, "ScopeInfoMap"),
+ 0x08135: (132, "HeapNumberMap"),
+ 0x08159: (133, "ForeignMap"),
+ 0x0817d: (64, "SymbolMap"),
+ 0x081a1: (68, "AsciiSymbolMap"),
+ 0x081c5: (65, "ConsSymbolMap"),
+ 0x081e9: (69, "ConsAsciiSymbolMap"),
+ 0x0820d: (66, "ExternalSymbolMap"),
+ 0x08231: (74, "ExternalSymbolWithAsciiDataMap"),
+ 0x08255: (70, "ExternalAsciiSymbolMap"),
+ 0x08279: (82, "ShortExternalSymbolMap"),
+ 0x0829d: (90, "ShortExternalSymbolWithAsciiDataMap"),
+ 0x082c1: (86, "ShortExternalAsciiSymbolMap"),
+ 0x082e5: (0, "StringMap"),
+ 0x08309: (4, "AsciiStringMap"),
+ 0x0832d: (1, "ConsStringMap"),
+ 0x08351: (5, "ConsAsciiStringMap"),
+ 0x08375: (3, "SlicedStringMap"),
+ 0x08399: (7, "SlicedAsciiStringMap"),
+ 0x083bd: (2, "ExternalStringMap"),
+ 0x083e1: (10, "ExternalStringWithAsciiDataMap"),
+ 0x08405: (6, "ExternalAsciiStringMap"),
+ 0x08429: (18, "ShortExternalStringMap"),
+ 0x0844d: (26, "ShortExternalStringWithAsciiDataMap"),
+ 0x08471: (22, "ShortExternalAsciiStringMap"),
+ 0x08495: (0, "UndetectableStringMap"),
+ 0x084b9: (4, "UndetectableAsciiStringMap"),
+ 0x084dd: (145, "FixedDoubleArrayMap"),
+ 0x08501: (134, "ByteArrayMap"),
+ 0x08525: (135, "FreeSpaceMap"),
+ 0x08549: (144, "ExternalPixelArrayMap"),
+ 0x0856d: (136, "ExternalByteArrayMap"),
+ 0x08591: (137, "ExternalUnsignedByteArrayMap"),
+ 0x085b5: (138, "ExternalShortArrayMap"),
+ 0x085d9: (139, "ExternalUnsignedShortArrayMap"),
+ 0x085fd: (140, "ExternalIntArrayMap"),
+ 0x08621: (141, "ExternalUnsignedIntArrayMap"),
+ 0x08645: (142, "ExternalFloatArrayMap"),
+ 0x08669: (163, "NonStrictArgumentsElementsMap"),
+ 0x0868d: (143, "ExternalDoubleArrayMap"),
+ 0x086b1: (129, "CodeMap"),
+ 0x086d5: (131, "GlobalPropertyCellMap"),
+ 0x086f9: (146, "OnePointerFillerMap"),
+ 0x0871d: (146, "TwoPointerFillerMap"),
+ 0x08741: (147, "AccessorInfoMap"),
+ 0x08765: (148, "AccessorPairMap"),
+ 0x08789: (149, "AccessCheckInfoMap"),
+ 0x087ad: (150, "InterceptorInfoMap"),
+ 0x087d1: (151, "CallHandlerInfoMap"),
+ 0x087f5: (152, "FunctionTemplateInfoMap"),
+ 0x08819: (153, "ObjectTemplateInfoMap"),
+ 0x0883d: (154, "SignatureInfoMap"),
+ 0x08861: (155, "TypeSwitchInfoMap"),
+ 0x08885: (156, "ScriptMap"),
+ 0x088a9: (157, "CodeCacheMap"),
+ 0x088cd: (158, "PolymorphicCodeCacheMap"),
+ 0x088f1: (159, "TypeFeedbackInfoMap"),
+ 0x08915: (160, "AliasedArgumentsEntryMap"),
+ 0x08939: (161, "DebugInfoMap"),
+ 0x0895d: (162, "BreakPointInfoMap"),
+ 0x08981: (163, "HashTableMap"),
+ 0x089a5: (163, "FunctionContextMap"),
+ 0x089c9: (163, "CatchContextMap"),
+ 0x089ed: (163, "WithContextMap"),
+ 0x08a11: (163, "BlockContextMap"),
+ 0x08a35: (163, "ModuleContextMap"),
+ 0x08a59: (163, "GlobalContextMap"),
+ 0x08a7d: (163, "NativeContextMap"),
+ 0x08aa1: (164, "SharedFunctionInfoMap"),
+ 0x08ac5: (165, "JSMessageObjectMap"),
+ 0x08ae9: (170, "ExternalMap"),
+ 0x08b0d: (170, "NeanderMap"),
+ 0x08b31: (170, ""),
}