Array length reduction should throw in strict mode if it can't delete an element.
When accessor getter callback is called the v8::PropertyCallbackInfo::ShouldThrowOnError() is always false, since according to ES6 there's no difference between strict and non-strict property loads. For the setter case the v8::PropertyCallbackInfo::ShouldThrowOnError() returns true if the property is set in strict context. Interceptors follow same idea: for getter, enumerator and query callbacks the v8::PropertyCallbackInfo::ShouldThrowOnError() is always false, and for setter and deleter callback the v8::PropertyCallbackInfo::ShouldThrowOnError() returns true in strict context. This CL also cleans up the CallApiGetterStub and removes bogus asserts from [arm] Push(reg1, reg2, ..., regN) that prevented from pushing a set of registers containing duplicates. BUG=v8:4267 LOG=Y Review URL: https://codereview.chromium.org/1587073003 Cr-Commit-Position: refs/heads/master@{#33438}
This commit is contained in:
parent
e709aa24c0
commit
1d3e837fcb
22
include/v8.h
22
include/v8.h
@ -3191,19 +3191,21 @@ class PropertyCallbackInfo {
|
||||
V8_INLINE Local<Object> This() const;
|
||||
V8_INLINE Local<Object> Holder() const;
|
||||
V8_INLINE ReturnValue<T> GetReturnValue() const;
|
||||
V8_INLINE bool ShouldThrowOnError() const;
|
||||
// This shouldn't be public, but the arm compiler needs it.
|
||||
static const int kArgsLength = 6;
|
||||
static const int kArgsLength = 7;
|
||||
|
||||
protected:
|
||||
friend class MacroAssembler;
|
||||
friend class internal::PropertyCallbackArguments;
|
||||
friend class internal::CustomArguments<PropertyCallbackInfo>;
|
||||
static const int kHolderIndex = 0;
|
||||
static const int kIsolateIndex = 1;
|
||||
static const int kReturnValueDefaultValueIndex = 2;
|
||||
static const int kReturnValueIndex = 3;
|
||||
static const int kDataIndex = 4;
|
||||
static const int kThisIndex = 5;
|
||||
static const int kShouldThrowOnErrorIndex = 0;
|
||||
static const int kHolderIndex = 1;
|
||||
static const int kIsolateIndex = 2;
|
||||
static const int kReturnValueDefaultValueIndex = 3;
|
||||
static const int kReturnValueIndex = 4;
|
||||
static const int kDataIndex = 5;
|
||||
static const int kThisIndex = 6;
|
||||
|
||||
V8_INLINE PropertyCallbackInfo(internal::Object** args) : args_(args) {}
|
||||
internal::Object** args_;
|
||||
@ -8262,6 +8264,12 @@ ReturnValue<T> PropertyCallbackInfo<T>::GetReturnValue() const {
|
||||
return ReturnValue<T>(&args_[kReturnValueIndex]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool PropertyCallbackInfo<T>::ShouldThrowOnError() const {
|
||||
typedef internal::Internals I;
|
||||
return args_[kShouldThrowOnErrorIndex] != I::IntToSmi(0);
|
||||
}
|
||||
|
||||
|
||||
Local<Primitive> Undefined(Isolate* isolate) {
|
||||
typedef internal::Object* S;
|
||||
|
@ -204,6 +204,19 @@ void Accessors::ArrayLengthSetter(
|
||||
if (JSArray::ObservableSetLength(array, length).is_null()) {
|
||||
isolate->OptionalRescheduleException(false);
|
||||
}
|
||||
|
||||
if (info.ShouldThrowOnError()) {
|
||||
uint32_t actual_new_len = 0;
|
||||
CHECK(array->length()->ToArrayLength(&actual_new_len));
|
||||
// Throw TypeError if there were non-deletable elements.
|
||||
if (actual_new_len != length) {
|
||||
Factory* factory = isolate->factory();
|
||||
isolate->Throw(*factory->NewTypeError(
|
||||
MessageTemplate::kStrictDeleteProperty,
|
||||
factory->NewNumberFromUint(actual_new_len - 1), array));
|
||||
isolate->OptionalRescheduleException(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1404,6 +1417,7 @@ static void ModuleGetExport(v8::Local<v8::Name> property,
|
||||
static void ModuleSetExport(v8::Local<v8::Name> property,
|
||||
v8::Local<v8::Value> value,
|
||||
const v8::PropertyCallbackInfo<void>& info) {
|
||||
if (!info.ShouldThrowOnError()) return;
|
||||
Handle<Name> name = v8::Utils::OpenHandle(*property);
|
||||
Isolate* isolate = name->GetIsolate();
|
||||
Handle<Object> exception =
|
||||
|
@ -70,16 +70,14 @@ v8::Local<v8::Value> FunctionCallbackArguments::Call(FunctionCallback f) {
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_CALL_2_VOID(Function, ReturnValue, Arg1, Arg2) \
|
||||
void PropertyCallbackArguments::Call(Function f, \
|
||||
Arg1 arg1, \
|
||||
Arg2 arg2) { \
|
||||
Isolate* isolate = this->isolate(); \
|
||||
VMState<EXTERNAL> state(isolate); \
|
||||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \
|
||||
PropertyCallbackInfo<ReturnValue> info(begin()); \
|
||||
f(arg1, arg2, info); \
|
||||
}
|
||||
#define WRITE_CALL_2_VOID(Function, ReturnValue, Arg1, Arg2) \
|
||||
void PropertyCallbackArguments::Call(Function f, Arg1 arg1, Arg2 arg2) { \
|
||||
Isolate* isolate = this->isolate(); \
|
||||
VMState<EXTERNAL> state(isolate); \
|
||||
ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); \
|
||||
PropertyCallbackInfo<ReturnValue> info(begin()); \
|
||||
f(arg1, arg2, info); \
|
||||
}
|
||||
|
||||
|
||||
FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
|
||||
|
@ -152,17 +152,19 @@ class PropertyCallbackArguments
|
||||
static const int kReturnValueDefaultValueIndex =
|
||||
T::kReturnValueDefaultValueIndex;
|
||||
static const int kIsolateIndex = T::kIsolateIndex;
|
||||
static const int kShouldThrowOnErrorIndex = T::kShouldThrowOnErrorIndex;
|
||||
|
||||
PropertyCallbackArguments(Isolate* isolate,
|
||||
Object* data,
|
||||
Object* self,
|
||||
JSObject* holder)
|
||||
PropertyCallbackArguments(Isolate* isolate, Object* data, Object* self,
|
||||
JSObject* holder, Object::ShouldThrow should_throw)
|
||||
: Super(isolate) {
|
||||
Object** values = this->begin();
|
||||
values[T::kThisIndex] = self;
|
||||
values[T::kHolderIndex] = holder;
|
||||
values[T::kDataIndex] = data;
|
||||
values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate);
|
||||
values[T::kShouldThrowOnErrorIndex] =
|
||||
Smi::FromInt(should_throw == Object::THROW_ON_ERROR ? 1 : 0);
|
||||
|
||||
// Here the hole is set as default value.
|
||||
// It cannot escape into js as it's remove in Call below.
|
||||
values[T::kReturnValueDefaultValueIndex] =
|
||||
|
@ -5377,34 +5377,39 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- sp[0] : name
|
||||
// -- sp[4 - kArgsLength*4] : PropertyCallbackArguments object
|
||||
// -- sp[0] : name
|
||||
// -- sp[4 .. (4 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- r2 : api_function_address
|
||||
// -- r2 : api_function_address
|
||||
// -----------------------------------
|
||||
|
||||
Register api_function_address = ApiGetterDescriptor::function_address();
|
||||
DCHECK(api_function_address.is(r2));
|
||||
|
||||
__ mov(r0, sp); // r0 = Handle<Name>
|
||||
__ add(r1, r0, Operand(1 * kPointerSize)); // r1 = PCA
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array and name handle.
|
||||
__ mov(r0, sp); // r0 = Handle<Name>
|
||||
__ add(r1, r0, Operand(1 * kPointerSize)); // r1 = v8::PCI::args_
|
||||
|
||||
const int kApiStackSpace = 1;
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, kApiStackSpace);
|
||||
|
||||
// Create PropertyAccessorInfo instance on the stack above the exit frame with
|
||||
// r1 (internal::Object** args_) as the data.
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
__ str(r1, MemOperand(sp, 1 * kPointerSize));
|
||||
__ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo&
|
||||
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
__ add(r1, sp, Operand(1 * kPointerSize)); // r1 = v8::PropertyCallbackInfo&
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, NULL,
|
||||
MemOperand(fp, 6 * kPointerSize), NULL);
|
||||
kStackUnwindSpace, NULL, return_value_operand, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -316,7 +316,6 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
// Push two registers. Pushes leftmost register first (to highest address).
|
||||
void Push(Register src1, Register src2, Condition cond = al) {
|
||||
DCHECK(!src1.is(src2));
|
||||
if (src1.code() > src2.code()) {
|
||||
stm(db_w, sp, src1.bit() | src2.bit(), cond);
|
||||
} else {
|
||||
@ -327,7 +326,6 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
// Push three registers. Pushes leftmost register first (to highest address).
|
||||
void Push(Register src1, Register src2, Register src3, Condition cond = al) {
|
||||
DCHECK(!AreAliased(src1, src2, src3));
|
||||
if (src1.code() > src2.code()) {
|
||||
if (src2.code() > src3.code()) {
|
||||
stm(db_w, sp, src1.bit() | src2.bit() | src3.bit(), cond);
|
||||
@ -347,7 +345,6 @@ class MacroAssembler: public Assembler {
|
||||
Register src3,
|
||||
Register src4,
|
||||
Condition cond = al) {
|
||||
DCHECK(!AreAliased(src1, src2, src3, src4));
|
||||
if (src1.code() > src2.code()) {
|
||||
if (src2.code() > src3.code()) {
|
||||
if (src3.code() > src4.code()) {
|
||||
@ -372,7 +369,6 @@ class MacroAssembler: public Assembler {
|
||||
// Push five registers. Pushes leftmost register first (to highest address).
|
||||
void Push(Register src1, Register src2, Register src3, Register src4,
|
||||
Register src5, Condition cond = al) {
|
||||
DCHECK(!AreAliased(src1, src2, src3, src4, src5));
|
||||
if (src1.code() > src2.code()) {
|
||||
if (src2.code() > src3.code()) {
|
||||
if (src3.code() > src4.code()) {
|
||||
|
@ -5817,17 +5817,21 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- sp[0] : name
|
||||
// -- sp[8 - kArgsLength*8] : PropertyCallbackArguments object
|
||||
// -- sp[0] : name
|
||||
// -- sp[8 .. (8 + kArgsLength*8)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- x2 : api_function_address
|
||||
// -- x2 : api_function_address
|
||||
// -----------------------------------
|
||||
|
||||
Register api_function_address = ApiGetterDescriptor::function_address();
|
||||
DCHECK(api_function_address.is(x2));
|
||||
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array and name handle.
|
||||
__ Mov(x0, masm->StackPointer()); // x0 = Handle<Name>
|
||||
__ Add(x1, x0, 1 * kPointerSize); // x1 = PCA
|
||||
__ Add(x1, x0, 1 * kPointerSize); // x1 = v8::PCI::args_
|
||||
|
||||
const int kApiStackSpace = 1;
|
||||
|
||||
@ -5838,20 +5842,22 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, x10, kApiStackSpace + kCallApiFunctionSpillSpace);
|
||||
|
||||
// Create PropertyAccessorInfo instance on the stack above the exit frame with
|
||||
// x1 (internal::Object** args_) as the data.
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
__ Poke(x1, 1 * kPointerSize);
|
||||
__ Add(x1, masm->StackPointer(), 1 * kPointerSize); // x1 = AccessorInfo&
|
||||
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
__ Add(x1, masm->StackPointer(), 1 * kPointerSize);
|
||||
// x1 = v8::PropertyCallbackInfo&
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
|
||||
const int spill_offset = 1 + kApiStackSpace;
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, NULL, spill_offset,
|
||||
MemOperand(fp, 6 * kPointerSize), NULL);
|
||||
return_value_operand, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5664,38 +5664,50 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : name
|
||||
// -- esp[8 - kArgsLength*4] : PropertyCallbackArguments object
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : name
|
||||
// -- esp[8 .. (8 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- edx : api_function_address
|
||||
// -- edx : api_function_address
|
||||
// -----------------------------------
|
||||
DCHECK(edx.is(ApiGetterDescriptor::function_address()));
|
||||
|
||||
// array for v8::Arguments::values_, handler for name and pointer
|
||||
// to the values (it considered as smi in GC).
|
||||
const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
|
||||
// Allocate space for opional callback address parameter in case
|
||||
// CPU profiler is active.
|
||||
const int kApiArgc = 2 + 1;
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Allocate v8::PropertyCallbackInfo object, arguments for callback and
|
||||
// space for optional callback address parameter (in case CPU profiler is
|
||||
// active) in non-GCed stack space.
|
||||
const int kApiArgc = 3 + 1;
|
||||
|
||||
Register api_function_address = edx;
|
||||
Register scratch = ebx;
|
||||
|
||||
// load address of name
|
||||
__ lea(scratch, Operand(esp, 1 * kPointerSize));
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array.
|
||||
__ lea(scratch, Operand(esp, 2 * kPointerSize));
|
||||
|
||||
PrepareCallApiFunction(masm, kApiArgc);
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
Operand info_object = ApiParameterOperand(3);
|
||||
__ mov(info_object, scratch);
|
||||
|
||||
__ sub(scratch, Immediate(kPointerSize));
|
||||
__ mov(ApiParameterOperand(0), scratch); // name.
|
||||
__ add(scratch, Immediate(kPointerSize));
|
||||
__ lea(scratch, info_object);
|
||||
__ mov(ApiParameterOperand(1), scratch); // arguments pointer.
|
||||
// Reserve space for optional callback address parameter.
|
||||
Operand thunk_last_arg = ApiParameterOperand(2);
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
Operand return_value_operand(
|
||||
ebp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
ApiParameterOperand(2), kStackSpace, nullptr,
|
||||
Operand(ebp, 7 * kPointerSize), NULL);
|
||||
thunk_last_arg, kStackUnwindSpace, nullptr,
|
||||
return_value_operand, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -595,37 +595,38 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
// Build AccessorInfo::args_ list on the stack and push property name below
|
||||
// the exit frame to make GC aware of them and store pointers to them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
|
||||
DCHECK(!scratch2().is(reg));
|
||||
DCHECK(!scratch3().is(reg));
|
||||
DCHECK(!scratch4().is(reg));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
|
||||
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
__ push(receiver());
|
||||
// Push data from AccessorInfo.
|
||||
Handle<Object> data(callback->data(), isolate());
|
||||
if (data->IsUndefined() || data->IsSmi()) {
|
||||
__ Move(scratch3(), data);
|
||||
__ Move(scratch2(), data);
|
||||
} else {
|
||||
Handle<WeakCell> cell =
|
||||
isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
|
||||
// The callback is alive if this instruction is executed,
|
||||
// so the weak cell is not cleared and points to data.
|
||||
__ GetWeakValue(scratch3(), cell);
|
||||
__ GetWeakValue(scratch2(), cell);
|
||||
}
|
||||
__ push(scratch3());
|
||||
__ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
|
||||
__ mov(scratch4(), scratch3());
|
||||
__ Push(scratch3(), scratch4());
|
||||
__ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ Push(scratch4(), reg);
|
||||
__ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_
|
||||
__ push(scratch2());
|
||||
__ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
|
||||
__ Push(scratch2(), scratch2());
|
||||
__ mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ Push(scratch2(), reg);
|
||||
__ Push(Smi::FromInt(0)); // should_throw_on_error -> false
|
||||
__ push(name());
|
||||
|
||||
// Abi for CallApiGetter
|
||||
@ -714,7 +715,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ push(receiver()); // receiver
|
||||
@ -731,6 +733,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
__ push(ip);
|
||||
__ mov(ip, Operand(name));
|
||||
__ Push(ip, value());
|
||||
__ Push(Smi::FromInt(language_mode));
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
|
||||
|
@ -646,18 +646,19 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
|
||||
|
||||
// Build AccessorInfo::args_ list on the stack and push property
|
||||
// name below the exit frame to make GC aware of them and store pointers to
|
||||
// them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
__ Push(receiver());
|
||||
|
||||
@ -673,18 +674,9 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
}
|
||||
__ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
|
||||
__ Mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg, name());
|
||||
|
||||
Register args_addr = scratch2();
|
||||
__ Add(args_addr, __ StackPointer(), kPointerSize);
|
||||
|
||||
// Stack at this point:
|
||||
// sp[40] callback data
|
||||
// sp[32] undefined
|
||||
// sp[24] undefined
|
||||
// sp[16] isolate
|
||||
// args_addr -> sp[8] reg
|
||||
// sp[0] name
|
||||
__ Push(scratch3(), scratch4(), scratch4(), scratch2(), reg);
|
||||
__ Push(Smi::FromInt(0)); // should_throw_on_error -> false
|
||||
__ Push(name());
|
||||
|
||||
// Abi for CallApiGetter.
|
||||
Register getter_address_reg = x2;
|
||||
@ -774,7 +766,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
@ -794,6 +787,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
}
|
||||
__ Mov(scratch2(), Operand(name));
|
||||
__ Push(receiver(), holder_reg, scratch1(), scratch2(), value());
|
||||
__ Push(Smi::FromInt(language_mode));
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
|
||||
|
@ -223,7 +223,8 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
|
||||
Handle<Name> name);
|
||||
Handle<Code> CompileStoreField(LookupIterator* it);
|
||||
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
|
||||
Handle<AccessorInfo> callback);
|
||||
Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode);
|
||||
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
|
||||
const CallOptimization& call_optimization,
|
||||
int accessor_index);
|
||||
|
@ -594,23 +594,29 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), receiver()));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), reg));
|
||||
|
||||
// Insert additional parameters into the stack frame above return address.
|
||||
DCHECK(!scratch3().is(reg));
|
||||
__ pop(scratch3()); // Get return address to place it below.
|
||||
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
__ push(receiver()); // receiver
|
||||
// Push data from AccessorInfo.
|
||||
Handle<Object> data(callback->data(), isolate());
|
||||
if (data->IsUndefined() || data->IsSmi()) {
|
||||
__ push(Immediate(data));
|
||||
} else {
|
||||
DCHECK(!scratch2().is(reg));
|
||||
Handle<WeakCell> cell =
|
||||
isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
|
||||
// The callback is alive if this instruction is executed,
|
||||
@ -623,13 +629,9 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
__ push(Immediate(isolate()->factory()->undefined_value()));
|
||||
__ push(Immediate(reinterpret_cast<int>(isolate())));
|
||||
__ push(reg); // holder
|
||||
|
||||
// Save a pointer to where we pushed the arguments. This will be
|
||||
// passed as the const PropertyAccessorInfo& to the C++ callback.
|
||||
__ push(esp);
|
||||
__ push(Immediate(Smi::FromInt(0))); // should_throw_on_error -> false
|
||||
|
||||
__ push(name()); // name
|
||||
|
||||
__ push(scratch3()); // Restore return address.
|
||||
|
||||
// Abi for CallApiGetter
|
||||
@ -731,7 +733,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ pop(scratch1()); // remove the return address
|
||||
@ -747,6 +750,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
}
|
||||
__ Push(name);
|
||||
__ push(value());
|
||||
__ push(Immediate(Smi::FromInt(language_mode)));
|
||||
__ push(scratch1()); // restore return address
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "src/macro-assembler.h"
|
||||
#include "src/prototype.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -1747,7 +1748,8 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
break;
|
||||
}
|
||||
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
||||
return compiler.CompileStoreCallback(receiver, lookup->name(), info);
|
||||
return compiler.CompileStoreCallback(receiver, lookup->name(), info,
|
||||
language_mode());
|
||||
} else if (accessors->IsAccessorPair()) {
|
||||
Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
|
||||
isolate());
|
||||
@ -2813,6 +2815,7 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
|
||||
Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2);
|
||||
Handle<Name> name = args.at<Name>(3);
|
||||
Handle<Object> value = args.at<Object>(4);
|
||||
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Handle<AccessorInfo> callback(
|
||||
@ -2828,8 +2831,10 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
|
||||
DCHECK(fun != NULL);
|
||||
|
||||
LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
|
||||
Object::ShouldThrow should_throw =
|
||||
is_sloppy(language_mode) ? Object::DONT_THROW : Object::THROW_ON_ERROR;
|
||||
PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
|
||||
*holder);
|
||||
*holder, should_throw);
|
||||
custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
|
||||
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
|
||||
return *value;
|
||||
|
@ -585,41 +585,50 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
// Build AccessorInfo::args_ list on the stack and push property name below
|
||||
// the exit frame to make GC aware of them and store pointers to them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
|
||||
DCHECK(!scratch2().is(reg));
|
||||
DCHECK(!scratch3().is(reg));
|
||||
DCHECK(!scratch4().is(reg));
|
||||
__ push(receiver());
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
|
||||
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
// Here and below +1 is for name() pushed after the args_ array.
|
||||
typedef PropertyCallbackArguments PCA;
|
||||
__ Subu(sp, sp, (PCA::kArgsLength + 1) * kPointerSize);
|
||||
__ sw(receiver(), MemOperand(sp, (PCA::kThisIndex + 1) * kPointerSize));
|
||||
Handle<Object> data(callback->data(), isolate());
|
||||
if (data->IsUndefined() || data->IsSmi()) {
|
||||
__ li(scratch3(), data);
|
||||
__ li(scratch2(), data);
|
||||
} else {
|
||||
Handle<WeakCell> cell =
|
||||
isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
|
||||
// The callback is alive if this instruction is executed,
|
||||
// so the weak cell is not cleared and points to data.
|
||||
__ GetWeakValue(scratch3(), cell);
|
||||
__ GetWeakValue(scratch2(), cell);
|
||||
}
|
||||
__ Subu(sp, sp, 6 * kPointerSize);
|
||||
__ sw(scratch3(), MemOperand(sp, 5 * kPointerSize));
|
||||
__ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
|
||||
__ sw(scratch3(), MemOperand(sp, 4 * kPointerSize));
|
||||
__ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
|
||||
__ li(scratch4(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ sw(scratch4(), MemOperand(sp, 2 * kPointerSize));
|
||||
__ sw(reg, MemOperand(sp, 1 * kPointerSize));
|
||||
__ sw(name(), MemOperand(sp, 0 * kPointerSize));
|
||||
__ Addu(scratch2(), sp, 1 * kPointerSize);
|
||||
__ sw(scratch2(), MemOperand(sp, (PCA::kDataIndex + 1) * kPointerSize));
|
||||
__ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
|
||||
__ sw(scratch2(),
|
||||
MemOperand(sp, (PCA::kReturnValueOffset + 1) * kPointerSize));
|
||||
__ sw(scratch2(), MemOperand(sp, (PCA::kReturnValueDefaultValueIndex + 1) *
|
||||
kPointerSize));
|
||||
__ li(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ sw(scratch2(), MemOperand(sp, (PCA::kIsolateIndex + 1) * kPointerSize));
|
||||
__ sw(reg, MemOperand(sp, (PCA::kHolderIndex + 1) * kPointerSize));
|
||||
// should_throw_on_error -> false
|
||||
DCHECK(Smi::FromInt(0) == nullptr);
|
||||
__ sw(zero_reg,
|
||||
MemOperand(sp, (PCA::kShouldThrowOnErrorIndex + 1) * kPointerSize));
|
||||
|
||||
__ sw(name(), MemOperand(sp, 0 * kPointerSize));
|
||||
|
||||
__ mov(a2, scratch2()); // Saved in case scratch2 == a1.
|
||||
// Abi for CallApiGetter.
|
||||
Register getter_address_reg = ApiGetterDescriptor::function_address();
|
||||
|
||||
@ -705,7 +714,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ Push(receiver(), holder_reg); // Receiver.
|
||||
@ -720,6 +730,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
__ push(at);
|
||||
__ li(at, Operand(name));
|
||||
__ Push(at, value());
|
||||
__ Push(Smi::FromInt(language_mode));
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
|
||||
|
@ -585,41 +585,50 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
// Build AccessorInfo::args_ list on the stack and push property name below
|
||||
// the exit frame to make GC aware of them and store pointers to them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
|
||||
DCHECK(!scratch2().is(reg));
|
||||
DCHECK(!scratch3().is(reg));
|
||||
DCHECK(!scratch4().is(reg));
|
||||
__ push(receiver());
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
|
||||
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
// Here and below +1 is for name() pushed after the args_ array.
|
||||
typedef PropertyCallbackArguments PCA;
|
||||
__ Dsubu(sp, sp, (PCA::kArgsLength + 1) * kPointerSize);
|
||||
__ sw(receiver(), MemOperand(sp, (PCA::kThisIndex + 1) * kPointerSize));
|
||||
Handle<Object> data(callback->data(), isolate());
|
||||
if (data->IsUndefined() || data->IsSmi()) {
|
||||
__ li(scratch3(), data);
|
||||
__ li(scratch2(), data);
|
||||
} else {
|
||||
Handle<WeakCell> cell =
|
||||
isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
|
||||
// The callback is alive if this instruction is executed,
|
||||
// so the weak cell is not cleared and points to data.
|
||||
__ GetWeakValue(scratch3(), cell);
|
||||
__ GetWeakValue(scratch2(), cell);
|
||||
}
|
||||
__ Dsubu(sp, sp, 6 * kPointerSize);
|
||||
__ sd(scratch3(), MemOperand(sp, 5 * kPointerSize));
|
||||
__ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
|
||||
__ sd(scratch3(), MemOperand(sp, 4 * kPointerSize));
|
||||
__ sd(scratch3(), MemOperand(sp, 3 * kPointerSize));
|
||||
__ li(scratch4(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ sd(scratch4(), MemOperand(sp, 2 * kPointerSize));
|
||||
__ sd(reg, MemOperand(sp, 1 * kPointerSize));
|
||||
__ sd(name(), MemOperand(sp, 0 * kPointerSize));
|
||||
__ Daddu(scratch2(), sp, 1 * kPointerSize);
|
||||
__ sd(scratch2(), MemOperand(sp, (PCA::kDataIndex + 1) * kPointerSize));
|
||||
__ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
|
||||
__ sd(scratch2(),
|
||||
MemOperand(sp, (PCA::kReturnValueOffset + 1) * kPointerSize));
|
||||
__ sd(scratch2(), MemOperand(sp, (PCA::kReturnValueDefaultValueIndex + 1) *
|
||||
kPointerSize));
|
||||
__ li(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ sd(scratch2(), MemOperand(sp, (PCA::kIsolateIndex + 1) * kPointerSize));
|
||||
__ sd(reg, MemOperand(sp, (PCA::kHolderIndex + 1) * kPointerSize));
|
||||
// should_throw_on_error -> false
|
||||
DCHECK(Smi::FromInt(0) == nullptr);
|
||||
__ sd(zero_reg,
|
||||
MemOperand(sp, (PCA::kShouldThrowOnErrorIndex + 1) * kPointerSize));
|
||||
|
||||
__ sd(name(), MemOperand(sp, 0 * kPointerSize));
|
||||
|
||||
__ mov(a2, scratch2()); // Saved in case scratch2 == a1.
|
||||
// Abi for CallApiGetter.
|
||||
Register getter_address_reg = ApiGetterDescriptor::function_address();
|
||||
|
||||
@ -705,7 +714,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ Push(receiver(), holder_reg); // Receiver.
|
||||
@ -720,6 +730,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
__ push(at);
|
||||
__ li(at, Operand(name));
|
||||
__ Push(at, value());
|
||||
__ Push(Smi::FromInt(language_mode));
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
|
||||
|
@ -593,37 +593,39 @@ void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
// Build AccessorInfo::args_ list on the stack and push property name below
|
||||
// the exit frame to make GC aware of them and store pointers to them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
|
||||
DCHECK(!scratch2().is(reg));
|
||||
DCHECK(!scratch3().is(reg));
|
||||
DCHECK(!scratch4().is(reg));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), receiver()));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), scratch4(), reg));
|
||||
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
__ push(receiver());
|
||||
// Push data from AccessorInfo.
|
||||
Handle<Object> data(callback->data(), isolate());
|
||||
if (data->IsUndefined() || data->IsSmi()) {
|
||||
__ Move(scratch3(), data);
|
||||
__ Move(scratch2(), data);
|
||||
} else {
|
||||
Handle<WeakCell> cell =
|
||||
isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
|
||||
// The callback is alive if this instruction is executed,
|
||||
// so the weak cell is not cleared and points to data.
|
||||
__ GetWeakValue(scratch3(), cell);
|
||||
__ GetWeakValue(scratch2(), cell);
|
||||
}
|
||||
__ push(scratch3());
|
||||
__ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
|
||||
__ mr(scratch4(), scratch3());
|
||||
__ Push(scratch3(), scratch4());
|
||||
__ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
__ Push(scratch4(), reg);
|
||||
__ push(name());
|
||||
__ push(scratch2());
|
||||
__ LoadRoot(scratch2(), Heap::kUndefinedValueRootIndex);
|
||||
__ Push(scratch2(), scratch2());
|
||||
__ mov(scratch2(), Operand(ExternalReference::isolate_address(isolate())));
|
||||
// should_throw_on_error -> false
|
||||
__ mov(scratch3(), Operand(Smi::FromInt(0)));
|
||||
__ Push(scratch2(), reg, scratch3(), name());
|
||||
|
||||
// Abi for CallApiGetter
|
||||
Register getter_address_reg = ApiGetterDescriptor::function_address();
|
||||
@ -711,7 +713,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ Push(receiver(), holder_reg); // receiver
|
||||
@ -727,6 +730,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
__ push(ip);
|
||||
__ mov(ip, Operand(name));
|
||||
__ Push(ip, value());
|
||||
__ Push(Smi::FromInt(language_mode));
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
__ TailCallRuntime(Runtime::kStoreCallbackProperty);
|
||||
|
@ -593,23 +593,28 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
// Insert additional parameters into the stack frame above return address.
|
||||
DCHECK(!scratch4().is(reg));
|
||||
__ PopReturnAddressTo(scratch4());
|
||||
DCHECK(!AreAliased(kScratchRegister, scratch2(), scratch3(), receiver()));
|
||||
DCHECK(!AreAliased(kScratchRegister, scratch2(), scratch3(), reg));
|
||||
|
||||
// Insert additional parameters into the stack frame above return address.
|
||||
__ PopReturnAddressTo(scratch3());
|
||||
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 6);
|
||||
__ Push(receiver()); // receiver
|
||||
Handle<Object> data(callback->data(), isolate());
|
||||
if (data->IsUndefined() || data->IsSmi()) {
|
||||
__ Push(data);
|
||||
} else {
|
||||
DCHECK(!scratch2().is(reg));
|
||||
Handle<WeakCell> cell =
|
||||
isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
|
||||
// The callback is alive if this instruction is executed,
|
||||
@ -617,17 +622,15 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
__ GetWeakValue(scratch2(), cell);
|
||||
__ Push(scratch2());
|
||||
}
|
||||
DCHECK(!kScratchRegister.is(reg));
|
||||
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
|
||||
__ Push(kScratchRegister); // return value
|
||||
__ Push(kScratchRegister); // return value default
|
||||
__ PushAddress(ExternalReference::isolate_address(isolate()));
|
||||
__ Push(reg); // holder
|
||||
__ Push(name()); // name
|
||||
// Save a pointer to where we pushed the arguments pointer. This will be
|
||||
// passed as the const PropertyAccessorInfo& to the C++ callback.
|
||||
__ Push(Smi::FromInt(0)); // should_throw_on_error -> false
|
||||
|
||||
__ PushReturnAddressFrom(scratch4());
|
||||
__ Push(name()); // name
|
||||
__ PushReturnAddressFrom(scratch3());
|
||||
|
||||
// Abi for CallApiGetter
|
||||
Register api_function_address = ApiGetterDescriptor::function_address();
|
||||
@ -722,7 +725,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ PopReturnAddressTo(scratch1());
|
||||
@ -738,6 +742,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
}
|
||||
__ Push(name);
|
||||
__ Push(value());
|
||||
__ Push(Smi::FromInt(language_mode));
|
||||
__ PushReturnAddressFrom(scratch1());
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
|
@ -594,23 +594,29 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
|
||||
|
||||
void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
Register reg, Handle<AccessorInfo> callback) {
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), receiver()));
|
||||
DCHECK(!AreAliased(scratch2(), scratch3(), reg));
|
||||
|
||||
// Insert additional parameters into the stack frame above return address.
|
||||
DCHECK(!scratch3().is(reg));
|
||||
__ pop(scratch3()); // Get return address to place it below.
|
||||
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
|
||||
// Build v8::PropertyCallbackInfo::args_ array on the stack and push property
|
||||
// name below the exit frame to make GC aware of them.
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kShouldThrowOnErrorIndex == 0);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 1);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 2);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 3);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 4);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 5);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 6);
|
||||
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 7);
|
||||
|
||||
__ push(receiver()); // receiver
|
||||
// Push data from AccessorInfo.
|
||||
Handle<Object> data(callback->data(), isolate());
|
||||
if (data->IsUndefined() || data->IsSmi()) {
|
||||
__ push(Immediate(data));
|
||||
} else {
|
||||
DCHECK(!scratch2().is(reg));
|
||||
Handle<WeakCell> cell =
|
||||
isolate()->factory()->NewWeakCell(Handle<HeapObject>::cast(data));
|
||||
// The callback is alive if this instruction is executed,
|
||||
@ -623,13 +629,9 @@ void NamedLoadHandlerCompiler::GenerateLoadCallback(
|
||||
__ push(Immediate(isolate()->factory()->undefined_value()));
|
||||
__ push(Immediate(reinterpret_cast<int>(isolate())));
|
||||
__ push(reg); // holder
|
||||
|
||||
// Save a pointer to where we pushed the arguments. This will be
|
||||
// passed as the const PropertyAccessorInfo& to the C++ callback.
|
||||
__ push(esp);
|
||||
__ push(Immediate(Smi::FromInt(0))); // should_throw_on_error -> false
|
||||
|
||||
__ push(name()); // name
|
||||
|
||||
__ push(scratch3()); // Restore return address.
|
||||
|
||||
// Abi for CallApiGetter
|
||||
@ -731,7 +733,8 @@ void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
|
||||
|
||||
|
||||
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback) {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
|
||||
LanguageMode language_mode) {
|
||||
Register holder_reg = Frontend(name);
|
||||
|
||||
__ pop(scratch1()); // remove the return address
|
||||
@ -747,6 +750,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
}
|
||||
__ Push(name);
|
||||
__ push(value());
|
||||
__ push(Immediate(Smi::FromInt(language_mode)));
|
||||
__ push(scratch1()); // restore return address
|
||||
|
||||
// Do tail-call to the runtime system.
|
||||
|
@ -5548,34 +5548,40 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- sp[0] : name
|
||||
// -- sp[4 - kArgsLength*4] : PropertyCallbackArguments object
|
||||
// -- sp[0] : name
|
||||
// -- sp[4 .. (4 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- a2 : api_function_address
|
||||
// -- a2 : api_function_address
|
||||
// -----------------------------------
|
||||
|
||||
Register api_function_address = ApiGetterDescriptor::function_address();
|
||||
DCHECK(api_function_address.is(a2));
|
||||
|
||||
__ mov(a0, sp); // a0 = Handle<Name>
|
||||
__ Addu(a1, a0, Operand(1 * kPointerSize)); // a1 = PCA
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array and name handle.
|
||||
__ mov(a0, sp); // a0 = Handle<Name>
|
||||
__ Addu(a1, a0, Operand(1 * kPointerSize)); // a1 = v8::PCI::args_
|
||||
|
||||
const int kApiStackSpace = 1;
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, kApiStackSpace);
|
||||
|
||||
// Create PropertyAccessorInfo instance on the stack above the exit frame with
|
||||
// a1 (internal::Object** args_) as the data.
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
__ sw(a1, MemOperand(sp, 1 * kPointerSize));
|
||||
__ Addu(a1, sp, Operand(1 * kPointerSize)); // a1 = AccessorInfo&
|
||||
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
__ Addu(a1, sp, Operand(1 * kPointerSize)); // a1 = v8::PropertyCallbackInfo&
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, kInvalidStackOffset,
|
||||
MemOperand(fp, 6 * kPointerSize), NULL);
|
||||
return_value_operand, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5607,34 +5607,41 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- sp[0] : name
|
||||
// -- sp[4 - kArgsLength*4] : PropertyCallbackArguments object
|
||||
// -- sp[0] : name
|
||||
// -- sp[8 .. (8 + kArgsLength*8)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- a2 : api_function_address
|
||||
// -- a2 : api_function_address
|
||||
// -----------------------------------
|
||||
|
||||
Register api_function_address = ApiGetterDescriptor::function_address();
|
||||
DCHECK(api_function_address.is(a2));
|
||||
|
||||
__ mov(a0, sp); // a0 = Handle<Name>
|
||||
__ Daddu(a1, a0, Operand(1 * kPointerSize)); // a1 = PCA
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array and name handle.
|
||||
__ mov(a0, sp); // a0 = Handle<Name>
|
||||
__ Daddu(a1, a0, Operand(1 * kPointerSize)); // a1 = v8::PCI::args_
|
||||
|
||||
const int kApiStackSpace = 1;
|
||||
FrameScope frame_scope(masm, StackFrame::MANUAL);
|
||||
__ EnterExitFrame(false, kApiStackSpace);
|
||||
|
||||
// Create PropertyAccessorInfo instance on the stack above the exit frame with
|
||||
// a1 (internal::Object** args_) as the data.
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
__ sd(a1, MemOperand(sp, 1 * kPointerSize));
|
||||
__ Daddu(a1, sp, Operand(1 * kPointerSize)); // a1 = AccessorInfo&
|
||||
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
__ Daddu(a1, sp, Operand(1 * kPointerSize));
|
||||
// a1 = v8::PropertyCallbackInfo&
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, kInvalidStackOffset,
|
||||
MemOperand(fp, 6 * kPointerSize), NULL);
|
||||
return_value_operand, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -371,6 +371,7 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT
|
||||
#undef PRINT_ELEMENTS
|
||||
|
||||
case DICTIONARY_ELEMENTS:
|
||||
os << "\n - elements: ";
|
||||
elements()->Print(os);
|
||||
break;
|
||||
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
|
||||
|
@ -1159,7 +1159,8 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(
|
||||
if (call_fun == nullptr) return isolate->factory()->undefined_value();
|
||||
|
||||
LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
|
||||
PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
|
||||
PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
|
||||
Object::DONT_THROW);
|
||||
v8::Local<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(name));
|
||||
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
|
||||
if (result.IsEmpty()) {
|
||||
@ -1224,7 +1225,8 @@ Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
|
||||
// earlier?
|
||||
|
||||
LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
|
||||
PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
|
||||
PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
|
||||
should_throw);
|
||||
args.Call(call_fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
|
||||
return Just(true);
|
||||
@ -3996,6 +3998,7 @@ Handle<Map> Map::Update(Handle<Map> map) {
|
||||
|
||||
|
||||
Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
|
||||
ShouldThrow should_throw,
|
||||
Handle<Object> value) {
|
||||
Isolate* isolate = it->isolate();
|
||||
// Make sure that the top context does not change when doing callbacks or
|
||||
@ -4009,7 +4012,7 @@ Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
v8::Local<v8::Value> result;
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(),
|
||||
*it->GetReceiver(), *holder);
|
||||
*it->GetReceiver(), *holder, should_throw);
|
||||
|
||||
if (it->IsElement()) {
|
||||
uint32_t index = it->index();
|
||||
@ -4090,7 +4093,8 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
|
||||
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
if (it->HolderIsReceiverOrHiddenPrototype()) {
|
||||
Maybe<bool> result = JSObject::SetPropertyWithInterceptor(it, value);
|
||||
Maybe<bool> result =
|
||||
JSObject::SetPropertyWithInterceptor(it, should_throw, value);
|
||||
if (result.IsNothing() || result.FromJust()) return result;
|
||||
} else {
|
||||
Maybe<PropertyAttributes> maybe_attributes =
|
||||
@ -5250,7 +5254,8 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
|
||||
// they throw. Here we should do the same.
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
if (handling == DONT_FORCE_FIELD) {
|
||||
Maybe<bool> result = JSObject::SetPropertyWithInterceptor(it, value);
|
||||
Maybe<bool> result =
|
||||
JSObject::SetPropertyWithInterceptor(it, should_throw, value);
|
||||
if (result.IsNothing() || result.FromJust()) return result;
|
||||
}
|
||||
break;
|
||||
@ -5373,7 +5378,8 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
|
||||
return Just(ABSENT);
|
||||
}
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(),
|
||||
*it->GetReceiver(), *holder);
|
||||
*it->GetReceiver(), *holder,
|
||||
Object::DONT_THROW);
|
||||
if (!interceptor->query()->IsUndefined()) {
|
||||
v8::Local<v8::Integer> result;
|
||||
if (it->IsElement()) {
|
||||
@ -6129,7 +6135,8 @@ Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
|
||||
Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it) {
|
||||
Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
|
||||
ShouldThrow should_throw) {
|
||||
Isolate* isolate = it->isolate();
|
||||
// Make sure that the top context does not change when doing callbacks or
|
||||
// interceptor calls.
|
||||
@ -6142,7 +6149,7 @@ Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it) {
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(),
|
||||
*it->GetReceiver(), *holder);
|
||||
*it->GetReceiver(), *holder, should_throw);
|
||||
v8::Local<v8::Boolean> result;
|
||||
if (it->IsElement()) {
|
||||
uint32_t index = it->index();
|
||||
@ -6240,7 +6247,10 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
|
||||
RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
|
||||
return Just(false);
|
||||
case LookupIterator::INTERCEPTOR: {
|
||||
Maybe<bool> result = JSObject::DeletePropertyWithInterceptor(it);
|
||||
ShouldThrow should_throw =
|
||||
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR;
|
||||
Maybe<bool> result =
|
||||
JSObject::DeletePropertyWithInterceptor(it, should_throw);
|
||||
// An exception was thrown in the interceptor. Propagate.
|
||||
if (isolate->has_pending_exception()) return Nothing<bool>();
|
||||
// Delete with interceptor succeeded. Return result.
|
||||
@ -8547,7 +8557,7 @@ static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate,
|
||||
return Just(true);
|
||||
}
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
|
||||
*object);
|
||||
*object, Object::DONT_THROW);
|
||||
v8::Local<v8::Object> result;
|
||||
if (!interceptor->enumerator()->IsUndefined()) {
|
||||
Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator());
|
||||
@ -16174,7 +16184,8 @@ MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(LookupIterator* it,
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
v8::Local<v8::Value> result;
|
||||
PropertyCallbackArguments args(isolate, interceptor->data(),
|
||||
*it->GetReceiver(), *holder);
|
||||
*it->GetReceiver(), *holder,
|
||||
Object::DONT_THROW);
|
||||
|
||||
if (it->IsElement()) {
|
||||
uint32_t index = it->index();
|
||||
|
@ -2066,7 +2066,7 @@ class JSObject: public JSReceiver {
|
||||
uint32_t limit);
|
||||
|
||||
MUST_USE_RESULT static Maybe<bool> SetPropertyWithInterceptor(
|
||||
LookupIterator* it, Handle<Object> value);
|
||||
LookupIterator* it, ShouldThrow should_throw, Handle<Object> value);
|
||||
|
||||
// SetLocalPropertyIgnoreAttributes converts callbacks to fields. We need to
|
||||
// grant an exemption to AccessorInfo callbacks in some cases.
|
||||
@ -2517,7 +2517,7 @@ class JSObject: public JSReceiver {
|
||||
PropertyAttributes attributes);
|
||||
|
||||
MUST_USE_RESULT static Maybe<bool> DeletePropertyWithInterceptor(
|
||||
LookupIterator* it);
|
||||
LookupIterator* it, ShouldThrow should_throw);
|
||||
|
||||
bool ReferencesObjectFromElements(FixedArray* elements,
|
||||
ElementsKind kind,
|
||||
|
@ -5585,10 +5585,10 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- sp[0] : name
|
||||
// -- sp[4 - kArgsLength*4] : PropertyCallbackArguments object
|
||||
// -- sp[0] : name
|
||||
// -- sp[4 .. (4 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- r5 : api_function_address
|
||||
// -- r5 : api_function_address
|
||||
// -----------------------------------
|
||||
|
||||
Register api_function_address = ApiGetterDescriptor::function_address();
|
||||
@ -5597,8 +5597,12 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
int apiStackSpace = 0;
|
||||
DCHECK(api_function_address.is(r5));
|
||||
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array and name handle.
|
||||
__ mr(r3, sp); // r0 = Handle<Name>
|
||||
__ addi(r4, r3, Operand(1 * kPointerSize)); // r4 = PCA
|
||||
__ addi(r4, r3, Operand(1 * kPointerSize)); // r4 = v8::PCI::args_
|
||||
|
||||
// If ABI passes Handles (pointer-sized struct) in a register:
|
||||
//
|
||||
@ -5630,19 +5634,20 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
__ addi(r3, sp, Operand(arg0Slot * kPointerSize));
|
||||
}
|
||||
|
||||
// Create PropertyAccessorInfo instance on the stack above the exit frame with
|
||||
// r4 (internal::Object** args_) as the data.
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
__ StoreP(r4, MemOperand(sp, accessorInfoSlot * kPointerSize));
|
||||
// r4 = AccessorInfo&
|
||||
__ addi(r4, sp, Operand(accessorInfoSlot * kPointerSize));
|
||||
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
// r4 = v8::PropertyCallbackInfo&
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
MemOperand return_value_operand(
|
||||
fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
kStackUnwindSpace, NULL,
|
||||
MemOperand(fp, 6 * kPointerSize), NULL);
|
||||
kStackUnwindSpace, NULL, return_value_operand, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1030,7 +1030,7 @@ namespace internal {
|
||||
F(LoadIC_MissFromStubFailure, 4, 1) \
|
||||
F(LoadPropertyWithInterceptor, 3, 1) \
|
||||
F(LoadPropertyWithInterceptorOnly, 3, 1) \
|
||||
F(StoreCallbackProperty, 5, 1) \
|
||||
F(StoreCallbackProperty, 6, 1) \
|
||||
F(StoreIC_Miss, 5, 1) \
|
||||
F(StoreIC_MissFromStubFailure, 5, 1) \
|
||||
F(StoreIC_Slow, 5, 1) \
|
||||
|
@ -5368,11 +5368,11 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rsp[0] : return address
|
||||
// -- rsp[8] : name
|
||||
// -- rsp[16 - kArgsLength*8] : PropertyCallbackArguments object
|
||||
// -- rsp[0] : return address
|
||||
// -- rsp[8] : name
|
||||
// -- rsp[16 .. (16 + kArgsLength*8)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- r8 : api_function_address
|
||||
// -- r8 : api_function_address
|
||||
// -----------------------------------
|
||||
|
||||
#if defined(__MINGW64__) || defined(_WIN64)
|
||||
@ -5388,23 +5388,25 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
DCHECK(api_function_address.is(r8));
|
||||
Register scratch = rax;
|
||||
|
||||
// v8::Arguments::values_ and handler for name.
|
||||
const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Allocate v8::AccessorInfo in non-GCed stack space.
|
||||
// Allocate v8::PropertyCallbackInfo in non-GCed stack space.
|
||||
const int kArgStackSpace = 1;
|
||||
|
||||
__ leap(name_arg, Operand(rsp, kPCOnStackSize));
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array.
|
||||
__ leap(scratch, Operand(rsp, 2 * kPointerSize));
|
||||
|
||||
PrepareCallApiFunction(masm, kArgStackSpace);
|
||||
__ leap(scratch, Operand(name_arg, 1 * kPointerSize));
|
||||
|
||||
// v8::PropertyAccessorInfo::args_.
|
||||
__ movp(StackSpaceOperand(0), scratch);
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
Operand info_object = StackSpaceOperand(0);
|
||||
__ movp(info_object, scratch);
|
||||
|
||||
__ leap(name_arg, Operand(scratch, -kPointerSize));
|
||||
// The context register (rsi) has been saved in PrepareCallApiFunction and
|
||||
// could be used to pass arguments.
|
||||
__ leap(accessor_info_arg, StackSpaceOperand(0));
|
||||
__ leap(accessor_info_arg, info_object);
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
@ -5414,13 +5416,12 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
DCHECK(!api_function_address.is(accessor_info_arg) &&
|
||||
!api_function_address.is(name_arg));
|
||||
|
||||
// The name handler is counted as an argument.
|
||||
StackArgumentsAccessor args(rbp, PropertyCallbackArguments::kArgsLength);
|
||||
Operand return_value_operand = args.GetArgumentOperand(
|
||||
PropertyCallbackArguments::kArgsLength - 1 -
|
||||
PropertyCallbackArguments::kReturnValueOffset);
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
Operand return_value_operand(
|
||||
rbp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref, getter_arg,
|
||||
kStackSpace, nullptr, return_value_operand, NULL);
|
||||
kStackUnwindSpace, nullptr, return_value_operand,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5344,38 +5344,50 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
|
||||
|
||||
void CallApiGetterStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : name
|
||||
// -- esp[8 - kArgsLength*4] : PropertyCallbackArguments object
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : name
|
||||
// -- esp[8 .. (8 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_
|
||||
// -- ...
|
||||
// -- edx : api_function_address
|
||||
// -- edx : api_function_address
|
||||
// -----------------------------------
|
||||
DCHECK(edx.is(ApiGetterDescriptor::function_address()));
|
||||
|
||||
// array for v8::Arguments::values_, handler for name and pointer
|
||||
// to the values (it considered as smi in GC).
|
||||
const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
|
||||
// Allocate space for opional callback address parameter in case
|
||||
// CPU profiler is active.
|
||||
const int kApiArgc = 2 + 1;
|
||||
// v8::PropertyCallbackInfo::args_ array and name handle.
|
||||
const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
|
||||
|
||||
// Allocate v8::PropertyCallbackInfo object, arguments for callback and
|
||||
// space for optional callback address parameter (in case CPU profiler is
|
||||
// active) in non-GCed stack space.
|
||||
const int kApiArgc = 3 + 1;
|
||||
|
||||
Register api_function_address = edx;
|
||||
Register scratch = ebx;
|
||||
|
||||
// load address of name
|
||||
__ lea(scratch, Operand(esp, 1 * kPointerSize));
|
||||
// Load address of v8::PropertyAccessorInfo::args_ array.
|
||||
__ lea(scratch, Operand(esp, 2 * kPointerSize));
|
||||
|
||||
PrepareCallApiFunction(masm, kApiArgc);
|
||||
// Create v8::PropertyCallbackInfo object on the stack and initialize
|
||||
// it's args_ field.
|
||||
Operand info_object = ApiParameterOperand(3);
|
||||
__ mov(info_object, scratch);
|
||||
|
||||
__ sub(scratch, Immediate(kPointerSize));
|
||||
__ mov(ApiParameterOperand(0), scratch); // name.
|
||||
__ add(scratch, Immediate(kPointerSize));
|
||||
__ lea(scratch, info_object);
|
||||
__ mov(ApiParameterOperand(1), scratch); // arguments pointer.
|
||||
// Reserve space for optional callback address parameter.
|
||||
Operand thunk_last_arg = ApiParameterOperand(2);
|
||||
|
||||
ExternalReference thunk_ref =
|
||||
ExternalReference::invoke_accessor_getter_callback(isolate());
|
||||
|
||||
// +3 is to skip prolog, return address and name handle.
|
||||
Operand return_value_operand(
|
||||
ebp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
|
||||
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
|
||||
ApiParameterOperand(2), kStackSpace, nullptr,
|
||||
Operand(ebp, 7 * kPointerSize), NULL);
|
||||
thunk_last_arg, kStackUnwindSpace, nullptr,
|
||||
return_value_operand, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -12792,6 +12792,203 @@ THREADED_TEST(Overriding) {
|
||||
}
|
||||
|
||||
|
||||
static void ShouldThrowOnErrorGetter(
|
||||
Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
Local<Boolean> should_throw_on_error =
|
||||
Boolean::New(isolate, info.ShouldThrowOnError());
|
||||
info.GetReturnValue().Set(should_throw_on_error);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value,
|
||||
const v8::PropertyCallbackInfo<T>& info) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
Local<Boolean> should_throw_on_error_value =
|
||||
Boolean::New(isolate, info.ShouldThrowOnError());
|
||||
CHECK(context->Global()
|
||||
->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"),
|
||||
should_throw_on_error_value)
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(AccessorShouldThrowOnError) {
|
||||
i::FLAG_strong_mode = true;
|
||||
LocalContext context;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
Local<Object> global = context->Global();
|
||||
|
||||
Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
|
||||
Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
|
||||
instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter,
|
||||
ShouldThrowOnErrorSetter<void>);
|
||||
|
||||
Local<v8::Object> instance = templ->GetFunction(context.local())
|
||||
.ToLocalChecked()
|
||||
->NewInstance(context.local())
|
||||
.ToLocalChecked();
|
||||
|
||||
CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
|
||||
|
||||
// SLOPPY mode
|
||||
Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_setter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
|
||||
// STRICT mode
|
||||
value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_setter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsTrue());
|
||||
|
||||
// STRONG mode
|
||||
value = v8_compile("'use strong';o.f")->Run(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
v8_compile("'use strong'; o.f = 153")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_setter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsTrue());
|
||||
}
|
||||
|
||||
|
||||
static void ShouldThrowOnErrorQuery(
|
||||
Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
info.GetReturnValue().Set(v8::None);
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
Local<Boolean> should_throw_on_error_value =
|
||||
Boolean::New(isolate, info.ShouldThrowOnError());
|
||||
CHECK(context->Global()
|
||||
->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"),
|
||||
should_throw_on_error_value)
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
|
||||
static void ShouldThrowOnErrorDeleter(
|
||||
Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
info.GetReturnValue().Set(v8::True(isolate));
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
Local<Boolean> should_throw_on_error_value =
|
||||
Boolean::New(isolate, info.ShouldThrowOnError());
|
||||
CHECK(context->Global()
|
||||
->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"),
|
||||
should_throw_on_error_value)
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
|
||||
static void ShouldThrowOnErrorPropertyEnumerator(
|
||||
const v8::PropertyCallbackInfo<v8::Array>& info) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
Local<v8::Array> names = v8::Array::New(isolate, 1);
|
||||
CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust());
|
||||
info.GetReturnValue().Set(names);
|
||||
|
||||
auto context = isolate->GetCurrentContext();
|
||||
Local<Boolean> should_throw_on_error_value =
|
||||
Boolean::New(isolate, info.ShouldThrowOnError());
|
||||
CHECK(context->Global()
|
||||
->Set(isolate->GetCurrentContext(),
|
||||
v8_str("should_throw_enumerator"),
|
||||
should_throw_on_error_value)
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(InterceptorShouldThrowOnError) {
|
||||
i::FLAG_strong_mode = true;
|
||||
LocalContext context;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
Local<Object> global = context->Global();
|
||||
|
||||
auto interceptor_templ = v8::ObjectTemplate::New(isolate);
|
||||
v8::NamedPropertyHandlerConfiguration handler(
|
||||
ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>,
|
||||
ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter,
|
||||
ShouldThrowOnErrorPropertyEnumerator);
|
||||
interceptor_templ->SetHandler(handler);
|
||||
|
||||
Local<v8::Object> instance =
|
||||
interceptor_templ->NewInstance(context.local()).ToLocalChecked();
|
||||
|
||||
CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
|
||||
|
||||
// SLOPPY mode
|
||||
Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_setter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
|
||||
v8_compile("delete o.f")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_deleter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
|
||||
v8_compile("Object.getOwnPropertyNames(o)")
|
||||
->Run(context.local())
|
||||
.ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_enumerator"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
|
||||
// STRICT mode
|
||||
value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_setter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsTrue());
|
||||
|
||||
v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_deleter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsTrue());
|
||||
|
||||
v8_compile("'use strict'; Object.getOwnPropertyNames(o)")
|
||||
->Run(context.local())
|
||||
.ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_enumerator"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
|
||||
// STRONG mode
|
||||
value = v8_compile("'use strong';o.f")->Run(context.local()).ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
v8_compile("'use strong'; o.f = 153")->Run(context.local()).ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_setter"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsTrue());
|
||||
|
||||
v8_compile("'use strong'; Object.getOwnPropertyNames(o)")
|
||||
->Run(context.local())
|
||||
.ToLocalChecked();
|
||||
value = global->Get(context.local(), v8_str("should_throw_enumerator"))
|
||||
.ToLocalChecked();
|
||||
CHECK(value->IsFalse());
|
||||
}
|
||||
|
||||
|
||||
static void IsConstructHandler(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
|
16
test/mjsunit/regress/regress-4267.js
Normal file
16
test/mjsunit/regress/regress-4267.js
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
"use strict";
|
||||
|
||||
var a = [];
|
||||
Object.defineProperty(a, "0", {configurable: false, value: 10});
|
||||
assertEquals(1, a.length);
|
||||
var setter = ()=>{ a.length = 0; };
|
||||
assertThrows(setter);
|
||||
assertThrows(setter);
|
||||
%OptimizeFunctionOnNextCall(setter);
|
||||
assertThrows(setter);
|
Loading…
Reference in New Issue
Block a user