Skip to content

Commit

Permalink
deps: cherry-pick backports to V8
Browse files Browse the repository at this point in the history
Included
  acb6779
  4e028bd
  75fe773
  c22bcd3
  49dec1a

Not included (cannot be applied cleanly)
  31450fc
  2b8a06b

PR-URL: #3351
Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information
targos authored and ofrobots committed Oct 14, 2015
1 parent d8011d1 commit 7fb128d
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 22 deletions.
13 changes: 13 additions & 0 deletions deps/v8/include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -5370,6 +5370,19 @@ class V8_EXPORT Isolate {
*/
static Isolate* GetCurrent();

/**
* Custom callback used by embedders to help V8 determine if it should abort
* when it throws and no internal handler is predicted to catch the
* exception. If --abort-on-uncaught-exception is used on the command line,
* then V8 will abort if either:
* - no custom callback is set.
* - the custom callback set returns true.
* Otherwise, the custom callback will not be called and V8 will not abort.
*/
typedef bool (*AbortOnUncaughtExceptionCallback)(Isolate*);
void SetAbortOnUncaughtExceptionCallback(
AbortOnUncaughtExceptionCallback callback);

/**
* Methods below this point require holding a lock (using Locker) in
* a multi-threaded environment.
Expand Down
41 changes: 28 additions & 13 deletions deps/v8/src/accessors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,37 @@ bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle<Map> map,
Isolate* isolate = name->GetIsolate();

switch (map->instance_type()) {
case JS_TYPED_ARRAY_TYPE:
// %TypedArray%.prototype is non-configurable, and so are the following
// named properties on %TypedArray%.prototype, so we can directly inline
// the field-load for typed array maps that still use their
// %TypedArray%.prototype.
if (JSFunction::cast(map->GetConstructor())->prototype() !=
map->prototype()) {
case JS_TYPED_ARRAY_TYPE: {
if (!CheckForName(name, isolate->factory()->length_string(),
JSTypedArray::kLengthOffset, object_offset) &&
!CheckForName(name, isolate->factory()->byte_length_string(),
JSTypedArray::kByteLengthOffset, object_offset) &&
!CheckForName(name, isolate->factory()->byte_offset_string(),
JSTypedArray::kByteOffsetOffset, object_offset)) {
return false;
}
return CheckForName(name, isolate->factory()->length_string(),
JSTypedArray::kLengthOffset, object_offset) ||
CheckForName(name, isolate->factory()->byte_length_string(),
JSTypedArray::kByteLengthOffset, object_offset) ||
CheckForName(name, isolate->factory()->byte_offset_string(),
JSTypedArray::kByteOffsetOffset, object_offset);

if (map->is_dictionary_map()) return false;

// Check if the property is overridden on the instance.
DescriptorArray* descriptors = map->instance_descriptors();
int descriptor = descriptors->SearchWithCache(*name, *map);
if (descriptor != DescriptorArray::kNotFound) return false;

Handle<Object> proto = Handle<Object>(map->prototype(), isolate);
if (!proto->IsJSReceiver()) return false;

// Check if the property is defined in the prototype chain.
LookupIterator it(proto, name);
if (!it.IsFound()) return false;

Object* original_proto =
JSFunction::cast(map->GetConstructor())->prototype();

// Property is not configurable. It is enough to verify that
// the holder is the same.
return *it.GetHolder<Object>() == original_proto;
}
case JS_DATA_VIEW_TYPE:
return CheckForName(name, isolate->factory()->byte_length_string(),
JSDataView::kByteLengthOffset, object_offset) ||
Expand Down
7 changes: 7 additions & 0 deletions deps/v8/src/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7160,6 +7160,13 @@ void Isolate::Exit() {
}


void Isolate::SetAbortOnUncaughtExceptionCallback(
AbortOnUncaughtExceptionCallback callback) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->SetAbortOnUncaughtExceptionCallback(callback);
}


Isolate::DisallowJavascriptExecutionScope::DisallowJavascriptExecutionScope(
Isolate* isolate,
Isolate::DisallowJavascriptExecutionScope::OnFailure on_failure)
Expand Down
29 changes: 22 additions & 7 deletions deps/v8/src/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1013,13 +1013,21 @@ Object* Isolate::Throw(Object* exception, MessageLocation* location) {
Handle<Object> message_obj = CreateMessage(exception_handle, location);
thread_local_top()->pending_message_obj_ = *message_obj;

// If the abort-on-uncaught-exception flag is specified, abort on any
// exception not caught by JavaScript, even when an external handler is
// present. This flag is intended for use by JavaScript developers, so
// print a user-friendly stack trace (not an internal one).
// For any exception not caught by JavaScript, even when an external
// handler is present:
// If the abort-on-uncaught-exception flag is specified, and if the
// embedder didn't specify a custom uncaught exception callback,
// or if the custom callback determined that V8 should abort, then
// abort.
if (FLAG_abort_on_uncaught_exception &&
PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) {
FLAG_abort_on_uncaught_exception = false; // Prevent endless recursion.
PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT &&
(!abort_on_uncaught_exception_callback_ ||
abort_on_uncaught_exception_callback_(
reinterpret_cast<v8::Isolate*>(this)))) {
// Prevent endless recursion.
FLAG_abort_on_uncaught_exception = false;
// This flag is intended for use by JavaScript developers, so
// print a user-friendly stack trace (not an internal one).
PrintF(stderr, "%s\n\nFROM\n",
MessageHandler::GetLocalizedMessage(this, message_obj).get());
PrintCurrentStackTrace(stderr);
Expand Down Expand Up @@ -1607,6 +1615,12 @@ void Isolate::SetCaptureStackTraceForUncaughtExceptions(
}


void Isolate::SetAbortOnUncaughtExceptionCallback(
v8::Isolate::AbortOnUncaughtExceptionCallback callback) {
abort_on_uncaught_exception_callback_ = callback;
}


Handle<Context> Isolate::native_context() {
return handle(context()->native_context());
}
Expand Down Expand Up @@ -1774,7 +1788,8 @@ Isolate::Isolate(bool enable_serializer)
next_unique_sfi_id_(0),
#endif
use_counter_callback_(NULL),
basic_block_profiler_(NULL) {
basic_block_profiler_(NULL),
abort_on_uncaught_exception_callback_(NULL) {
{
base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
CHECK(thread_data_table_);
Expand Down
6 changes: 6 additions & 0 deletions deps/v8/src/isolate.h
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,9 @@ class Isolate {
int frame_limit,
StackTrace::StackTraceOptions options);

void SetAbortOnUncaughtExceptionCallback(
v8::Isolate::AbortOnUncaughtExceptionCallback callback);

enum PrintStackMode { kPrintStackConcise, kPrintStackVerbose };
void PrintCurrentStackTrace(FILE* out);
void PrintStack(StringStream* accumulator,
Expand Down Expand Up @@ -1366,6 +1369,9 @@ class Isolate {

std::set<Cancelable*> cancelable_tasks_;

v8::Isolate::AbortOnUncaughtExceptionCallback
abort_on_uncaught_exception_callback_;

friend class ExecutionAccess;
friend class HandleScopeImplementer;
friend class OptimizingCompileDispatcher;
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/src/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -3932,14 +3932,14 @@ class ScopeInfo : public FixedArray {
FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(FIELD_ACCESSORS)
#undef FIELD_ACCESSORS

private:
enum {
#define DECL_INDEX(name) k##name,
FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(DECL_INDEX)
#undef DECL_INDEX
kVariablePartIndex
};

private:
// The layout of the variable part of a ScopeInfo is as follows:
// 1. ParameterEntries:
// This part stores the names of the parameters for function scopes. One
Expand Down
30 changes: 30 additions & 0 deletions deps/v8/test/cctest/test-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21826,4 +21826,34 @@ TEST(EstimatedContextSize) {
v8::HandleScope scope(isolate);
LocalContext env;
CHECK(50000 < env->EstimatedSize());


static int nb_uncaught_exception_callback_calls = 0;


bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
++nb_uncaught_exception_callback_calls;
return false;
}


TEST(AbortOnUncaughtExceptionNoAbort) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New(isolate);
LocalContext env(NULL, global_template);

i::FLAG_abort_on_uncaught_exception = true;
isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);

CompileRun("function boom() { throw new Error(\"boom\") }");

v8::Local<v8::Object> global_object = env->Global();
v8::Local<v8::Function> foo =
v8::Local<v8::Function>::Cast(global_object->Get(v8_str("boom")));

foo->Call(global_object, 0, NULL);

CHECK_EQ(1, nb_uncaught_exception_callback_calls);
}
37 changes: 37 additions & 0 deletions deps/v8/test/mjsunit/regress/regress-typedarray-length.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,43 @@ assertEquals(undefined, get(a));
assertEquals(undefined, get(a));
})();

(function() {
"use strict";

class MyTypedArray extends Int32Array {
constructor(length) {
super(length);
}
}

a = new MyTypedArray(1024);

get = function(a) {
return a.length;
}

assertEquals(1024, get(a));
assertEquals(1024, get(a));
assertEquals(1024, get(a));
%OptimizeFunctionOnNextCall(get);
assertEquals(1024, get(a));
})();

(function() {
"use strict";
var a = new Uint8Array(4);
Object.defineProperty(a, "length", {get: function() { return "blah"; }});
get = function(a) {
return a.length;
}

assertEquals("blah", get(a));
assertEquals("blah", get(a));
assertEquals("blah", get(a));
%OptimizeFunctionOnNextCall(get);
assertEquals("blah", get(a));
})();

// Ensure we cannot delete length, byteOffset, byteLength.
assertTrue(Int32Array.prototype.hasOwnProperty("length"));
assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset"));
Expand Down
12 changes: 11 additions & 1 deletion deps/v8/tools/gen-postmortem-metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@
'value': 'JavaScriptFrameConstants::kFunctionOffset' },
{ 'name': 'off_fp_args',
'value': 'JavaScriptFrameConstants::kLastParameterOffset' },

{ 'name': 'scopeinfo_idx_nparams',
'value': 'ScopeInfo::kParameterCount' },
{ 'name': 'scopeinfo_idx_nstacklocals',
'value': 'ScopeInfo::kStackLocalCount' },
{ 'name': 'scopeinfo_idx_ncontextlocals',
'value': 'ScopeInfo::kContextLocalCount' },
{ 'name': 'scopeinfo_idx_first_vars',
'value': 'ScopeInfo::kVariablePartIndex' },
];

#
Expand All @@ -141,12 +150,13 @@
'HeapObject, map, Map, kMapOffset',
'JSObject, elements, Object, kElementsOffset',
'FixedArray, data, uintptr_t, kHeaderSize',
'JSTypedArray, length, Object, kLengthOffset',
'Map, instance_attributes, int, kInstanceAttributesOffset',
'Map, inobject_properties_of_constructor_function_index_offset, int, kInObjectPropertiesOrConstructorFunctionIndexOffset',
'Map, instance_size, int, kInstanceSizeOffset',
'Map, bit_field, char, kBitFieldOffset',
'Map, bit_field2, char, kBitField2Offset',
'Map, bit_field3, SMI, kBitField3Offset',
'Map, bit_field3, int, kBitField3Offset',
'Map, prototype, Object, kPrototypeOffset',
'NameDictionaryShape, prefix_size, int, kPrefixSize',
'NameDictionaryShape, entry_size, int, kEntrySize',
Expand Down

0 comments on commit 7fb128d

Please sign in to comment.