// See assembler-arm-inl.h for inlined constructors
Operand::Operand(Handle<Object> handle) {
+#ifdef DEBUG
+ Isolate* isolate = Isolate::Current();
+#endif
+ ALLOW_HANDLE_DEREF(isolate, "using and embedding raw address");
rm_ = no_reg;
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
- ASSERT(!HEAP->InNewSpace(obj));
+ ASSERT(!isolate->heap()->InNewSpace(obj));
if (obj->IsHeapObject()) {
imm32_ = reinterpret_cast<intptr_t>(handle.location());
rmode_ = RelocInfo::EMBEDDED_OBJECT;
} else {
// no relocation needed
- imm32_ = reinterpret_cast<intptr_t>(obj);
+ imm32_ = reinterpret_cast<intptr_t>(obj);
rmode_ = RelocInfo::NONE32;
}
}
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
- Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};
virtual void PrintDataTo(StringStream* stream);
- Handle<JSFunction> target() const { return hydrogen()->target(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
public:
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
-
- Handle<SharedFunctionInfo> shared_info() { return hydrogen()->shared_info(); }
};
pushed_arguments_index,
pushed_arguments_count);
bool has_closure_id = !info()->closure().is_null() &&
- *info()->closure() != *environment->closure();
+ !info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
- for (int i = 0; i < deoptimization_literals_.length(); i++) {
- literals->set(i, *deoptimization_literals_[i]);
+ { ALLOW_HANDLE_DEREF(isolate(),
+ "copying a ZoneList of handles into a FixedArray");
+ for (int i = 0; i < deoptimization_literals_.length(); i++) {
+ literals->set(i, *deoptimization_literals_[i]);
+ }
+ data->SetLiteralArray(*literals);
}
- data->SetLiteralArray(*literals);
data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
void LCodeGen::DoConstantT(LConstantT* instr) {
Handle<Object> value = instr->value();
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (value->IsSmi()) {
__ mov(ToRegister(instr->result()), Operand(value));
} else {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
+ int formal_parameter_count,
int arity,
LInstruction* instr,
CallKind call_kind,
R1State r1_state) {
- bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
- function->shared()->formal_parameter_count() == arity;
+ bool dont_adapt_arguments =
+ formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+ bool can_invoke_directly =
+ dont_adapt_arguments || formal_parameter_count == arity;
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
// Set r0 to arguments count if adaption is not needed. Assumes that r0
// is available to write to at this point.
- if (!function->NeedsArgumentsAdaption()) {
+ if (dont_adapt_arguments) {
__ mov(r0, Operand(arity));
}
} else {
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(arity);
- __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
+ ParameterCount expected(formal_parameter_count);
+ __ InvokeFunction(
+ function, expected, count, CALL_FUNCTION, generator, call_kind);
}
// Restore context.
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
- CallKnownFunction(instr->function(),
+ CallKnownFunction(instr->hydrogen()->function(),
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_METHOD,
ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(instr->HasPointerMap());
- if (instr->known_function().is_null()) {
+ Handle<JSFunction> known_function = instr->hydrogen()->known_function();
+ if (known_function.is_null()) {
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
__ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else {
- CallKnownFunction(instr->known_function(),
+ CallKnownFunction(known_function,
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_METHOD,
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(r0));
- CallKnownFunction(instr->target(),
+ CallKnownFunction(instr->hydrogen()->target(),
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_FUNCTION,
void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
Register reg = ToRegister(instr->value());
Handle<JSFunction> target = instr->hydrogen()->target();
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (isolate()->heap()->InNewSpace(*target)) {
Register reg = ToRegister(instr->value());
Handle<JSGlobalPropertyCell> cell =
Register scratch = ToRegister(instr->temp());
Register scratch2 = ToRegister(instr->temp2());
Handle<JSFunction> constructor = instr->hydrogen()->constructor();
- Handle<Map> initial_map(constructor->initial_map());
+ Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
ASSERT(initial_map->pre_allocated_property_fields() +
initial_map->unused_property_fields() -
initial_map->inobject_properties() == 0);
- // Allocate memory for the object. The initial map might change when
- // the constructor's prototype changes, but instance size and property
- // counts remain unchanged (if slack tracking finished).
- ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
__ Allocate(instance_size, result, scratch, scratch2, deferred->entry(),
TAG_OBJECT);
void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
Register result = ToRegister(instr->result());
- Handle<JSFunction> constructor = instr->hydrogen()->constructor();
- Handle<Map> initial_map(constructor->initial_map());
+ Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
// TODO(3095996): Get rid of this. For now, we need to make the
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
- Handle<FixedArray> literals(instr->environment()->closure()->literals());
+ Handle<FixedArray> literals = instr->hydrogen()->literals();
ElementsKind boilerplate_elements_kind =
instr->hydrogen()->boilerplate_elements_kind();
AllocationSiteMode allocation_site_mode =
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
- Handle<FixedArray> literals(instr->environment()->closure()->literals());
+ Handle<FixedArray> literals = instr->hydrogen()->literals();
Handle<FixedArray> constant_properties =
instr->hydrogen()->constant_properties();
__ mov(r0, Operand(Smi::FromInt(flags)));
// Pick the right runtime function or stub to call.
- int properties_count = constant_properties->length() / 2;
+ int properties_count = instr->hydrogen()->constant_properties_length() / 2;
if (instr->hydrogen()->depth() > 1) {
__ Push(r3, r2, r1, r0);
CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (!pretenure && shared_info->num_literals() == 0) {
- FastNewClosureStub stub(shared_info->language_mode(),
- shared_info->is_generator());
- __ mov(r1, Operand(shared_info));
+ if (!pretenure && instr->hydrogen()->has_no_literals()) {
+ FastNewClosureStub stub(instr->hydrogen()->language_mode(),
+ instr->hydrogen()->is_generator());
+ __ mov(r1, Operand(instr->hydrogen()->shared_info()));
__ push(r1);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else {
- __ mov(r2, Operand(shared_info));
- __ mov(r1, Operand(pretenure
- ? factory()->true_value()
- : factory()->false_value()));
+ __ mov(r2, Operand(instr->hydrogen()->shared_info()));
+ __ mov(r1, Operand(pretenure ? factory()->true_value()
+ : factory()->false_value()));
__ Push(cp, r2, r1);
CallRuntime(Runtime::kNewClosure, 3, instr);
}
// Generate a direct call to a known function. Expects the function
// to be in r1.
void CallKnownFunction(Handle<JSFunction> function,
+ int formal_parameter_count,
int arity,
LInstruction* instr,
CallKind call_kind,
Condition cond) {
ASSERT(RelocInfo::IsCodeTarget(rmode));
// 'code' is always generated ARM code, never THUMB code
+ ALLOW_HANDLE_DEREF(isolate(), "embedding raw address");
Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
}
RelocInfo::Mode rmode,
TypeFeedbackId ast_id,
Condition cond) {
+ ALLOW_HANDLE_DEREF(isolate(), "using raw address");
return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond);
}
rmode = RelocInfo::CODE_TARGET_WITH_ID;
}
// 'code' is always generated ARM code, never THUMB code
+ ALLOW_HANDLE_DEREF(isolate(), "embedding raw address");
Call(reinterpret_cast<Address>(code.location()), rmode, cond, mode);
}
void MacroAssembler::LoadHeapObject(Register result,
Handle<HeapObject> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "using raw address");
if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(object);
void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper,
LoadHeapObject(r1, function);
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
- ParameterCount expected(function->shared()->formal_parameter_count());
// We call indirectly through the code field in the function to
// allow recompilation to take effect without changing any of the
// call sites.
void LoadHeapObject(Register dst, Handle<HeapObject> object);
void LoadObject(Register result, Handle<Object> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "heap object check");
if (object->IsHeapObject()) {
LoadHeapObject(result, Handle<HeapObject>::cast(object));
} else {
CallKind call_kind);
void InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper,
CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(optimization.constant_function(), arguments_,
+ Handle<JSFunction> fun = optimization.constant_function();
+ __ InvokeFunction(fun, ParameterCount(fun), arguments_,
JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- __ InvokeFunction(
- function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// r2: function name.
__ bind(&slow);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
- __ InvokeFunction(
- function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// r2: function name.
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- __ InvokeFunction(
- function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// r2: function name.
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(
- function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
// Call the JavaScript setter with receiver and value on the stack.
__ Push(r1, r0);
ParameterCount actual(1);
- __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ ParameterCount expected(setter);
+ __ InvokeFunction(setter, expected, actual,
+ CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
} else {
// If we generate a global code snippet for deoptimization only, remember
// the place to continue after deoptimization.
// Call the JavaScript getter with the receiver on the stack.
__ push(r0);
ParameterCount actual(0);
- __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ ParameterCount expected(getter);
+ __ InvokeFunction(getter, expected, actual,
+ CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
} else {
// If we generate a global code snippet for deoptimization only, remember
// the place to continue after deoptimization.
#define V8_CODE_H_
#include "allocation.h"
+#include "handles.h"
+#include "objects.h"
namespace v8 {
namespace internal {
: reg_(reg), immediate_(0) { }
explicit ParameterCount(int immediate)
: reg_(no_reg), immediate_(immediate) { }
+ explicit ParameterCount(Handle<JSFunction> f)
+ : reg_(no_reg), immediate_(f->shared()->formal_parameter_count()) { }
bool is_reg() const { return !reg_.is(no_reg); }
bool is_immediate() const { return !is_reg(); }
Timer timer(this, &time_taken_to_codegen_);
ASSERT(chunk_ != NULL);
ASSERT(graph_ != NULL);
+ // Deferred handles reference objects that were accessible during
+ // graph creation. To make sure that we don't encounter inconsistencies
+ // between graph creation and code generation, we disallow accessing
+ // objects through deferred handles during the latter, with exceptions.
+ HandleDereferenceGuard no_deref_deferred(
+ isolate(), HandleDereferenceGuard::DISALLOW_DEFERRED);
Handle<Code> optimized_code = chunk_->Codegen();
if (optimized_code.is_null()) {
info()->set_bailout_reason("code generation failed");
Handle<JSGlobalPropertyCell> Factory::NewJSGlobalPropertyCell(
Handle<Object> value) {
+ ALLOW_HANDLE_DEREF(isolate(),
+ "converting a handle into a global property cell");
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateJSGlobalPropertyCell(*value),
inline bool Handle<T>::is_identical_to(const Handle<T> other) const {
ASSERT(location_ == NULL ||
reinterpret_cast<Address>(*location_) != kZapValue);
-#ifdef DEBUG
- if (FLAG_enable_slow_asserts) {
- Isolate* isolate = Isolate::Current();
- CHECK(isolate->AllowHandleDereference() ||
- !isolate->optimizing_compiler_thread()->IsOptimizerThread());
- }
-#endif // DEBUG
+ // Dereferencing deferred handles to check object equality is safe.
+ SLOW_ASSERT(IsDereferenceAllowed(true) && other.IsDereferenceAllowed(true));
return *location_ == *other.location_;
}
inline T* Handle<T>::operator*() const {
ASSERT(location_ != NULL);
ASSERT(reinterpret_cast<Address>(*location_) != kHandleZapValue);
- SLOW_ASSERT(Isolate::Current()->AllowHandleDereference());
+ SLOW_ASSERT(IsDereferenceAllowed(false));
return *BitCast<T**>(location_);
}
inline T** Handle<T>::location() const {
ASSERT(location_ == NULL ||
reinterpret_cast<Address>(*location_) != kZapValue);
- SLOW_ASSERT(Isolate::Current()->AllowHandleDereference());
+ SLOW_ASSERT(IsDereferenceAllowed(false));
return location_;
}
+#ifdef DEBUG
+template <typename T>
+bool Handle<T>::IsDereferenceAllowed(bool allow_deferred) const {
+ if (location_ == NULL) return true;
+ Object* object = *BitCast<T**>(location_);
+ if (object->IsSmi()) return true;
+ HeapObject* heap_object = HeapObject::cast(object);
+ Isolate* isolate = heap_object->GetIsolate();
+ Object** handle = reinterpret_cast<Object**>(location_);
+ Object** roots_array_start = isolate->heap()->roots_array_start();
+ if (roots_array_start <= handle &&
+ handle < roots_array_start + Heap::kStrongRootListLength) {
+ return true;
+ }
+ switch (isolate->HandleDereferenceGuardState()) {
+ case HandleDereferenceGuard::ALLOW:
+ return true;
+ case HandleDereferenceGuard::DISALLOW:
+ return false;
+ case HandleDereferenceGuard::DISALLOW_DEFERRED:
+ // Accessing maps and internalized strings is safe.
+ if (heap_object->IsMap()) return true;
+ if (heap_object->IsInternalizedString()) return true;
+ return allow_deferred || !isolate->IsDeferredHandle(handle);
+ }
+ return false;
+}
+#endif
+
+
HandleScope::HandleScope(Isolate* isolate) {
v8::ImplementationUtilities::HandleScopeData* current =
HandleDereferenceGuard::HandleDereferenceGuard(Isolate* isolate, State state)
: isolate_(isolate) {
- old_state_ = isolate_->AllowHandleDereference();
- isolate_->SetAllowHandleDereference(state == ALLOW);
+ old_state_ = isolate_->HandleDereferenceGuardState();
+ isolate_->SetHandleDereferenceGuardState(state);
}
HandleDereferenceGuard::~HandleDereferenceGuard() {
- isolate_->SetAllowHandleDereference(old_state_);
+ isolate_->SetHandleDereferenceGuardState(old_state_);
}
#endif
INLINE(T** location() const);
template <class S> static Handle<T> cast(Handle<S> that) {
- T::cast(*that);
- return Handle<T>(reinterpret_cast<T**>(that.location()));
+ T::cast(*reinterpret_cast<T**>(that.location_));
+ return Handle<T>(reinterpret_cast<T**>(that.location_));
}
static Handle<T> null() { return Handle<T>(); }
// implementation in api.h.
inline Handle<T> EscapeFrom(v8::HandleScope* scope);
+#ifdef DEBUG
+ bool IsDereferenceAllowed(bool allow_deferred) const;
+#endif // DEBUG
+
private:
T** location_;
class HandleDereferenceGuard BASE_EMBEDDED {
public:
- enum State { ALLOW, DISALLOW };
+ enum State { ALLOW, DISALLOW, DISALLOW_DEFERRED };
#ifndef DEBUG
HandleDereferenceGuard(Isolate* isolate, State state) { }
~HandleDereferenceGuard() { }
inline ~HandleDereferenceGuard();
private:
Isolate* isolate_;
- bool old_state_;
+ State old_state_;
#endif
};
+#ifdef DEBUG
+#define ALLOW_HANDLE_DEREF(isolate, why_this_is_safe) \
+ HandleDereferenceGuard allow_deref(isolate, \
+ HandleDereferenceGuard::ALLOW);
+#else
+#define ALLOW_HANDLE_DEREF(isolate, why_this_is_safe)
+#endif // DEBUG
+
} } // namespace v8::internal
#endif // V8_HANDLES_H_
}
-bool HArrayLiteral::IsCopyOnWrite() const {
- if (!boilerplate_object_->IsJSObject()) return false;
- return Handle<JSObject>::cast(boilerplate_object_)->elements()->map() ==
- HEAP->fixed_cow_array_map();
-}
-
-
void HBinaryOperation::PrintDataTo(StringStream* stream) {
left()->PrintNameTo(stream);
stream->Add(" ");
int argument_count)
: HBinaryCall(context, function, argument_count),
known_function_(known_function) {
+ formal_parameter_count_ = known_function.is_null()
+ ? 0 : known_function->shared()->formal_parameter_count();
}
virtual Representation RequiredInputRepresentation(int index) {
HValue* context() { return first(); }
HValue* function() { return second(); }
Handle<JSFunction> known_function() { return known_function_; }
+ int formal_parameter_count() const { return formal_parameter_count_; }
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
private:
Handle<JSFunction> known_function_;
+ int formal_parameter_count_;
};
class HCallConstantFunction: public HCall<0> {
public:
HCallConstantFunction(Handle<JSFunction> function, int argument_count)
- : HCall<0>(argument_count), function_(function) { }
+ : HCall<0>(argument_count),
+ function_(function),
+ formal_parameter_count_(function->shared()->formal_parameter_count()) {}
Handle<JSFunction> function() const { return function_; }
+ int formal_parameter_count() const { return formal_parameter_count_; }
bool IsApplyFunction() const {
return function_->code() ==
private:
Handle<JSFunction> function_;
+ int formal_parameter_count_;
};
class HCallKnownGlobal: public HCall<0> {
public:
HCallKnownGlobal(Handle<JSFunction> target, int argument_count)
- : HCall<0>(argument_count), target_(target) { }
+ : HCall<0>(argument_count),
+ target_(target),
+ formal_parameter_count_(target->shared()->formal_parameter_count()) { }
virtual void PrintDataTo(StringStream* stream);
Handle<JSFunction> target() const { return target_; }
+ int formal_parameter_count() const { return formal_parameter_count_; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
private:
Handle<JSFunction> target_;
+ int formal_parameter_count_;
};
Handle<Object> handle() {
if (handle_.is_null()) {
- handle_ = FACTORY->NewNumber(double_value_, TENURED);
+ handle_ = isolate()->factory()->NewNumber(double_value_, TENURED);
}
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
ASSERT(has_int32_value_ || !handle_->IsSmi());
return handle_;
}
}
ASSERT(!handle_.is_null());
- HandleDereferenceGuard allow_dereference_for_immovable_check(
- isolate(), HandleDereferenceGuard::ALLOW);
Heap* heap = isolate()->heap();
ASSERT(unique_id_ != UniqueValueId(heap->minus_zero_value()));
ASSERT(unique_id_ != UniqueValueId(heap->nan_value()));
SetOperandAt(0, context);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
+ constructor_initial_map_ = constructor->has_initial_map()
+ ? Handle<Map>(constructor->initial_map())
+ : Handle<Map>::null();
+ // If slack tracking finished, the instance size and property counts
+ // remain unchanged so that we can allocate memory for the object.
+ ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
}
// Maximum instance size for which allocations will be inlined.
HValue* context() { return OperandAt(0); }
Handle<JSFunction> constructor() { return constructor_; }
+ Handle<Map> constructor_initial_map() { return constructor_initial_map_; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
virtual Handle<Map> GetMonomorphicJSObjectMap() {
- ASSERT(constructor()->has_initial_map());
- return Handle<Map>(constructor()->initial_map());
+ ASSERT(!constructor_initial_map_.is_null());
+ return constructor_initial_map_;
}
virtual HType CalculateInferredType();
// virtual bool IsDeletable() const { return true; }
Handle<JSFunction> constructor_;
+ Handle<Map> constructor_initial_map_;
};
public:
HArrayLiteral(HValue* context,
Handle<HeapObject> boilerplate_object,
+ Handle<FixedArray> literals,
int length,
int literal_index,
int depth,
AllocationSiteMode mode)
: HMaterializedLiteral<1>(literal_index, depth, mode),
length_(length),
- boilerplate_object_(boilerplate_object) {
+ boilerplate_object_(boilerplate_object),
+ literals_(literals) {
SetOperandAt(0, context);
SetGVNFlag(kChangesNewSpacePromotion);
+
+ boilerplate_elements_kind_ = boilerplate_object_->IsJSObject()
+ ? Handle<JSObject>::cast(boilerplate_object_)->GetElementsKind()
+ : TERMINAL_FAST_ELEMENTS_KIND;
+
+ is_copy_on_write_ = boilerplate_object_->IsJSObject() &&
+ (Handle<JSObject>::cast(boilerplate_object_)->elements()->map() ==
+ HEAP->fixed_cow_array_map());
}
HValue* context() { return OperandAt(0); }
ElementsKind boilerplate_elements_kind() const {
- if (!boilerplate_object_->IsJSObject()) {
- return TERMINAL_FAST_ELEMENTS_KIND;
- }
- return Handle<JSObject>::cast(boilerplate_object_)->GetElementsKind();
+ return boilerplate_elements_kind_;
}
Handle<HeapObject> boilerplate_object() const { return boilerplate_object_; }
+ Handle<FixedArray> literals() const { return literals_; }
int length() const { return length_; }
- bool IsCopyOnWrite() const;
+ bool IsCopyOnWrite() const { return is_copy_on_write_; }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
private:
int length_;
Handle<HeapObject> boilerplate_object_;
+ Handle<FixedArray> literals_;
+ ElementsKind boilerplate_elements_kind_;
+ bool is_copy_on_write_;
};
public:
HObjectLiteral(HValue* context,
Handle<FixedArray> constant_properties,
+ Handle<FixedArray> literals,
bool fast_elements,
int literal_index,
int depth,
bool has_function)
: HMaterializedLiteral<1>(literal_index, depth),
constant_properties_(constant_properties),
+ constant_properties_length_(constant_properties->length()),
+ literals_(literals),
fast_elements_(fast_elements),
has_function_(has_function) {
SetOperandAt(0, context);
Handle<FixedArray> constant_properties() const {
return constant_properties_;
}
+ int constant_properties_length() const {
+ return constant_properties_length_;
+ }
+ Handle<FixedArray> literals() const { return literals_; }
bool fast_elements() const { return fast_elements_; }
bool has_function() const { return has_function_; }
private:
Handle<FixedArray> constant_properties_;
- bool fast_elements_;
- bool has_function_;
+ int constant_properties_length_;
+ Handle<FixedArray> literals_;
+ bool fast_elements_ : 1;
+ bool has_function_ : 1;
};
HFunctionLiteral(HValue* context,
Handle<SharedFunctionInfo> shared,
bool pretenure)
- : shared_info_(shared), pretenure_(pretenure) {
+ : shared_info_(shared),
+ pretenure_(pretenure),
+ has_no_literals_(shared->num_literals() == 0),
+ is_generator_(shared->is_generator()),
+ language_mode_(shared->language_mode()) {
SetOperandAt(0, context);
set_representation(Representation::Tagged());
SetGVNFlag(kChangesNewSpacePromotion);
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
bool pretenure() const { return pretenure_; }
+ bool has_no_literals() const { return has_no_literals_; }
+ bool is_generator() const { return is_generator_; }
+ LanguageMode language_mode() const { return language_mode_; }
private:
virtual bool IsDeletable() const { return true; }
Handle<SharedFunctionInfo> shared_info_;
- bool pretenure_;
+ bool pretenure_ : 1;
+ bool has_no_literals_ : 1;
+ bool is_generator_ : 1;
+ LanguageMode language_mode_;
};
void HGraph::Verify(bool do_full_verify) const {
- // Allow dereferencing for debug mode verification.
- HandleDereferenceGuard allow_handle_deref(isolate(),
- HandleDereferenceGuard::ALLOW);
+ ALLOW_HANDLE_DEREF(isolate(), "debug mode verification");
for (int i = 0; i < blocks_.length(); i++) {
HBasicBlock* block = blocks_.at(i);
pointer_size,
DONT_TRACK_ALLOCATION_SITE);
} else {
+ Handle<FixedArray> closure_literals(closure->literals(), isolate());
literal = AddInstruction(
new(zone()) HObjectLiteral(context,
expr->constant_properties(),
+ closure_literals,
expr->fast_elements(),
expr->literal_index(),
expr->depth(),
HValue* context = environment()->LookupContext();
HInstruction* literal;
- Handle<FixedArray> literals(environment()->closure()->literals());
+ Handle<FixedArray> literals(environment()->closure()->literals(), isolate());
Handle<Object> raw_boilerplate(literals->get(expr->literal_index()),
isolate());
literal = AddInstruction(
new(zone()) HArrayLiteral(context,
original_boilerplate_object,
+ literals,
length,
expr->literal_index(),
expr->depth(),
void HTracer::TraceLithium(const char* name, LChunk* chunk) {
ASSERT(!FLAG_parallel_recompilation);
- HandleDereferenceGuard allow_handle_deref(chunk->isolate(),
- HandleDereferenceGuard::ALLOW);
+ ALLOW_HANDLE_DEREF(chunk->isolate(), "debug output");
Trace(name, chunk->graph(), chunk);
}
void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
ASSERT(!FLAG_parallel_recompilation);
- HandleDereferenceGuard allow_handle_deref(graph->isolate(),
- HandleDereferenceGuard::ALLOW);
+ ALLOW_HANDLE_DEREF(graph->isolate(), "debug output");
Trace(name, graph, NULL);
}
Immediate::Immediate(Handle<Object> handle) {
+#ifdef DEBUG
+ Isolate* isolate = Isolate::Current();
+#endif
+ ALLOW_HANDLE_DEREF(isolate,
+ "using and embedding raw address, heap object check");
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
- ASSERT(!HEAP->InNewSpace(obj));
+ ASSERT(!isolate->heap()->InNewSpace(obj));
if (obj->IsHeapObject()) {
x_ = reinterpret_cast<intptr_t>(handle.location());
rmode_ = RelocInfo::EMBEDDED_OBJECT;
void Assembler::emit(Handle<Object> handle) {
+ ALLOW_HANDLE_DEREF(isolate(), "heap object check");
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
ASSERT(!isolate()->heap()->InNewSpace(obj));
}
+void Assembler::emit(Handle<Code> code,
+ RelocInfo::Mode rmode,
+ TypeFeedbackId id) {
+ ALLOW_HANDLE_DEREF(isolate(), "embedding raw address");
+ emit(reinterpret_cast<intptr_t>(code.location()), rmode, id);
+}
+
+
void Assembler::emit(const Immediate& x) {
if (x.rmode_ == RelocInfo::INTERNAL_REFERENCE) {
Label* label = reinterpret_cast<Label*>(x.x_);
EnsureSpace ensure_space(this);
ASSERT(RelocInfo::IsCodeTarget(rmode));
EMIT(0xE8);
- emit(reinterpret_cast<intptr_t>(code.location()), rmode, ast_id);
+ emit(code, rmode, ast_id);
}
EnsureSpace ensure_space(this);
ASSERT(RelocInfo::IsCodeTarget(rmode));
EMIT(0xE9);
- emit(reinterpret_cast<intptr_t>(code.location()), rmode);
+ emit(code, rmode);
}
// 0000 1111 1000 tttn #32-bit disp
EMIT(0x0F);
EMIT(0x80 | cc);
- emit(reinterpret_cast<intptr_t>(code.location()), RelocInfo::CODE_TARGET);
+ emit(code, RelocInfo::CODE_TARGET);
}
}
static Operand Cell(Handle<JSGlobalPropertyCell> cell) {
+ ALLOW_HANDLE_DEREF(Isolate::Current(), "embedding raw address");
return Operand(reinterpret_cast<int32_t>(cell.location()),
RelocInfo::GLOBAL_PROPERTY_CELL);
}
inline void emit(uint32_t x,
RelocInfo::Mode rmode,
TypeFeedbackId id = TypeFeedbackId::None());
+ inline void emit(Handle<Code> code,
+ RelocInfo::Mode rmode,
+ TypeFeedbackId id = TypeFeedbackId::None());
inline void emit(const Immediate& x);
inline void emit_w(const Immediate& x);
pushed_arguments_index,
pushed_arguments_count);
bool has_closure_id = !info()->closure().is_null() &&
- *info()->closure() != *environment->closure();
+ !info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
- for (int i = 0; i < deoptimization_literals_.length(); i++) {
- literals->set(i, *deoptimization_literals_[i]);
+ { ALLOW_HANDLE_DEREF(isolate(),
+ "copying a ZoneList of handles into a FixedArray");
+ for (int i = 0; i < deoptimization_literals_.length(); i++) {
+ literals->set(i, *deoptimization_literals_[i]);
+ }
+ data->SetLiteralArray(*literals);
}
- data->SetLiteralArray(*literals);
data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
void LCodeGen::DoConstantT(LConstantT* instr) {
Register reg = ToRegister(instr->result());
Handle<Object> handle = instr->value();
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (handle->IsHeapObject()) {
__ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
} else {
ASSERT(!operand->IsDoubleRegister());
if (operand->IsConstantOperand()) {
Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (object->IsSmi()) {
__ Push(Handle<Smi>::cast(object));
} else {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
+ int formal_parameter_count,
int arity,
LInstruction* instr,
CallKind call_kind,
EDIState edi_state) {
- bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
- function->shared()->formal_parameter_count() == arity;
+ bool dont_adapt_arguments =
+ formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+ bool can_invoke_directly =
+ dont_adapt_arguments || formal_parameter_count == arity;
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
// Set eax to arguments count if adaption is not needed. Assumes that eax
// is available to write to at this point.
- if (!function->NeedsArgumentsAdaption()) {
+ if (dont_adapt_arguments) {
__ mov(eax, arity);
}
// Invoke function directly.
__ SetCallKind(ecx, call_kind);
- if (*function == *info()->closure()) {
+ if (function.is_identical_to(info()->closure())) {
__ CallSelf();
} else {
__ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
SafepointGenerator generator(
this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(arity);
- __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
+ ParameterCount expected(formal_parameter_count);
+ __ InvokeFunction(
+ function, expected, count, CALL_FUNCTION, generator, call_kind);
}
}
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
- CallKnownFunction(instr->function(),
+ CallKnownFunction(instr->hydrogen()->function(),
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_METHOD,
ASSERT(ToRegister(instr->function()).is(edi));
ASSERT(instr->HasPointerMap());
- if (instr->known_function().is_null()) {
+ Handle<JSFunction> known_function = instr->hydrogen()->known_function();
+ if (known_function.is_null()) {
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(
ParameterCount count(instr->arity());
__ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
} else {
- CallKnownFunction(instr->known_function(),
+ CallKnownFunction(known_function,
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_METHOD,
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(eax));
- CallKnownFunction(instr->target(),
+ CallKnownFunction(instr->hydrogen()->target(),
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_FUNCTION,
Register result = ToRegister(instr->result());
Register scratch = ToRegister(instr->temp());
Handle<JSFunction> constructor = instr->hydrogen()->constructor();
- Handle<Map> initial_map(constructor->initial_map());
+ Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
ASSERT(initial_map->pre_allocated_property_fields() +
initial_map->unused_property_fields() -
initial_map->inobject_properties() == 0);
- // Allocate memory for the object. The initial map might change when
- // the constructor's prototype changes, but instance size and property
- // counts remain unchanged (if slack tracking finished).
- ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
__ Allocate(instance_size, result, no_reg, scratch, deferred->entry(),
TAG_OBJECT);
void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
Register result = ToRegister(instr->result());
- Handle<JSFunction> constructor = instr->hydrogen()->constructor();
- Handle<Map> initial_map(constructor->initial_map());
+ Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
// TODO(3095996): Get rid of this. For now, we need to make the
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
- Handle<FixedArray> literals(instr->environment()->closure()->literals());
+ Handle<FixedArray> literals = instr->hydrogen()->literals();
ElementsKind boilerplate_elements_kind =
instr->hydrogen()->boilerplate_elements_kind();
AllocationSiteMode allocation_site_mode =
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
- Handle<FixedArray> literals(instr->environment()->closure()->literals());
+ Handle<FixedArray> literals = instr->hydrogen()->literals();
Handle<FixedArray> constant_properties =
instr->hydrogen()->constant_properties();
// Set up the parameters to the stub/runtime call and pick the right
// runtime function or stub to call.
- int properties_count = constant_properties->length() / 2;
+ int properties_count = instr->hydrogen()->constant_properties_length() / 2;
if (instr->hydrogen()->depth() > 1) {
__ PushHeapObject(literals);
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ASSERT(ToRegister(instr->context()).is(esi));
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (!pretenure && shared_info->num_literals() == 0) {
- FastNewClosureStub stub(shared_info->language_mode(),
- shared_info->is_generator());
- __ push(Immediate(shared_info));
+ if (!pretenure && instr->hydrogen()->has_no_literals()) {
+ FastNewClosureStub stub(instr->hydrogen()->language_mode(),
+ instr->hydrogen()->is_generator());
+ __ push(Immediate(instr->hydrogen()->shared_info()));
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else {
__ push(esi);
- __ push(Immediate(shared_info));
- __ push(Immediate(pretenure
- ? factory()->true_value()
- : factory()->false_value()));
+ __ push(Immediate(instr->hydrogen()->shared_info()));
+ __ push(Immediate(pretenure ? factory()->true_value()
+ : factory()->false_value()));
CallRuntime(Runtime::kNewClosure, 3, instr);
}
}
// Generate a direct call to a known function. Expects the function
// to be in edi.
void CallKnownFunction(Handle<JSFunction> function,
+ int formal_parameter_count,
int arity,
LInstruction* instr,
CallKind call_kind,
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
- Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};
virtual void PrintDataTo(StringStream* stream);
- Handle<JSFunction> target() const { return hydrogen()->target(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
-
- Handle<SharedFunctionInfo> shared_info() { return hydrogen()->shared_info(); }
};
void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper,
LoadHeapObject(edi, function);
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
- ParameterCount expected(function->shared()->formal_parameter_count());
// We call indirectly through the code field in the function to
// allow recompilation to take effect without changing any of the
// call sites.
void MacroAssembler::LoadHeapObject(Register result,
Handle<HeapObject> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "embedding raw address");
if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(object);
void MacroAssembler::PushHeapObject(Handle<HeapObject> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "using raw address");
if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(object);
void PushHeapObject(Handle<HeapObject> object);
void LoadObject(Register result, Handle<Object> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "heap object check");
if (object->IsHeapObject()) {
LoadHeapObject(result, Handle<HeapObject>::cast(object));
} else {
CallKind call_kind);
void InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper,
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(optimization.constant_function(), arguments_,
+ Handle<JSFunction> fun = optimization.constant_function();
+ __ InvokeFunction(fun, ParameterCount(fun), arguments_,
JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind);
__ bind(&miss);
// ecx: function name.
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), CALL_AS_METHOD);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// ecx: function name.
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), CALL_AS_METHOD);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// ecx: function name.
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
__ push(edx);
__ push(eax);
ParameterCount actual(1);
- __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ ParameterCount expected(setter);
+ __ InvokeFunction(setter, expected, actual,
+ CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
} else {
// If we generate a global code snippet for deoptimization only, remember
// the place to continue after deoptimization.
// Call the JavaScript getter with the receiver on the stack.
__ push(edx);
ParameterCount actual(0);
- __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ ParameterCount expected(getter);
+ __ InvokeFunction(getter, expected, actual,
+ CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
} else {
// If we generate a global code snippet for deoptimization only, remember
// the place to continue after deoptimization.
}
+#ifdef DEBUG
+bool Isolate::IsDeferredHandle(Object** handle) {
+ // Each DeferredHandles instance keeps the handles to one job in the
+ // parallel recompilation queue, containing a list of blocks. Each block
+ // contains kHandleBlockSize handles except for the first block, which may
+ // not be fully filled.
+ // We iterate through all the blocks to see whether the argument handle
+ // belongs to one of the blocks. If so, it is deferred.
+ for (DeferredHandles* deferred = deferred_handles_head_;
+ deferred != NULL;
+ deferred = deferred->next_) {
+ List<Object**>* blocks = &deferred->blocks_;
+ for (int i = 0; i < blocks->length(); i++) {
+ Object** block_limit = (i == 0) ? deferred->first_block_limit_
+ : blocks->at(i) + kHandleBlockSize;
+ if (blocks->at(i) <= handle && handle < block_limit) return true;
+ }
+ }
+ return false;
+}
+#endif // DEBUG
+
+
void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
// The ARM simulator has a separate JS stack. We therefore register
// the C++ try catch handler with the simulator and get back an
memset(code_kind_statistics_, 0,
sizeof(code_kind_statistics_[0]) * Code::NUMBER_OF_KINDS);
- allow_compiler_thread_handle_deref_ = true;
- allow_execution_thread_handle_deref_ = true;
+ compiler_thread_handle_deref_state_ = HandleDereferenceGuard::ALLOW;
+ execution_thread_handle_deref_state_ = HandleDereferenceGuard::ALLOW;
#endif
#ifdef ENABLE_DEBUGGER_SUPPORT
#ifdef DEBUG
-bool Isolate::AllowHandleDereference() {
- if (allow_execution_thread_handle_deref_ &&
- allow_compiler_thread_handle_deref_) {
+HandleDereferenceGuard::State Isolate::HandleDereferenceGuardState() {
+ if (execution_thread_handle_deref_state_ == HandleDereferenceGuard::ALLOW &&
+ compiler_thread_handle_deref_state_ == HandleDereferenceGuard::ALLOW) {
// Short-cut to avoid polling thread id.
- return true;
+ return HandleDereferenceGuard::ALLOW;
}
if (FLAG_parallel_recompilation &&
optimizing_compiler_thread()->IsOptimizerThread()) {
- return allow_compiler_thread_handle_deref_;
+ return compiler_thread_handle_deref_state_;
} else {
- return allow_execution_thread_handle_deref_;
+ return execution_thread_handle_deref_state_;
}
}
-void Isolate::SetAllowHandleDereference(bool allow) {
+void Isolate::SetHandleDereferenceGuardState(
+ HandleDereferenceGuard::State state) {
if (FLAG_parallel_recompilation &&
optimizing_compiler_thread()->IsOptimizerThread()) {
- allow_compiler_thread_handle_deref_ = allow;
+ compiler_thread_handle_deref_state_ = state;
} else {
- allow_execution_thread_handle_deref_ = allow;
+ execution_thread_handle_deref_state_ = state;
}
}
#endif
int* code_kind_statistics() { return code_kind_statistics_; }
- bool AllowHandleDereference();
+ HandleDereferenceGuard::State HandleDereferenceGuardState();
- void SetAllowHandleDereference(bool allow);
+ void SetHandleDereferenceGuardState(HandleDereferenceGuard::State state);
#endif
#if defined(V8_TARGET_ARCH_ARM) && !defined(__arm__) || \
void LinkDeferredHandles(DeferredHandles* deferred_handles);
void UnlinkDeferredHandles(DeferredHandles* deferred_handles);
+#ifdef DEBUG
+ bool IsDeferredHandle(Object** location);
+#endif // DEBUG
+
OptimizingCompilerThread* optimizing_compiler_thread() {
return &optimizing_compiler_thread_;
}
JSObject::SpillInformation js_spill_information_;
int code_kind_statistics_[Code::NUMBER_OF_KINDS];
- bool allow_compiler_thread_handle_deref_;
- bool allow_execution_thread_handle_deref_;
+ HandleDereferenceGuard::State compiler_thread_handle_deref_state_;
+ HandleDereferenceGuard::State execution_thread_handle_deref_state_;
#endif
#ifdef ENABLE_DEBUGGER_SUPPORT
RelocInfo::kApplyMask;
// Needed to find target_object and runtime_entry on X64
Assembler* origin = desc.origin;
+ ALLOW_HANDLE_DEREF(GetIsolate(), "embedding raw addresses into code");
for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
+ ALLOW_HANDLE_DEREF(isolate(), "using and embedding raw address");
// If there is no relocation info, emit the value of the handle efficiently
// (possibly using less that 8 bytes for the value).
if (RelocInfo::IsNone(mode)) {
pushed_arguments_index,
pushed_arguments_count);
bool has_closure_id = !info()->closure().is_null() &&
- *info()->closure() != *environment->closure();
+ !info()->closure().is_identical_to(environment->closure());
int closure_id = has_closure_id
? DefineDeoptimizationLiteral(environment->closure())
: Translation::kSelfLiteralId;
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
- for (int i = 0; i < deoptimization_literals_.length(); i++) {
- literals->set(i, *deoptimization_literals_[i]);
+ { ALLOW_HANDLE_DEREF(isolate(),
+ "copying a ZoneList of handles into a FixedArray");
+ for (int i = 0; i < deoptimization_literals_.length(); i++) {
+ literals->set(i, *deoptimization_literals_[i]);
+ }
+ data->SetLiteralArray(*literals);
}
- data->SetLiteralArray(*literals);
data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
void LCodeGen::DoConstantT(LConstantT* instr) {
Handle<Object> value = instr->value();
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (value->IsSmi()) {
__ Move(ToRegister(instr->result()), value);
} else {
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
+ int formal_parameter_count,
int arity,
LInstruction* instr,
CallKind call_kind,
RDIState rdi_state) {
- bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
- function->shared()->formal_parameter_count() == arity;
+ bool dont_adapt_arguments =
+ formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+ bool can_invoke_directly =
+ dont_adapt_arguments || formal_parameter_count == arity;
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
// Set rax to arguments count if adaption is not needed. Assumes that rax
// is available to write to at this point.
- if (!function->NeedsArgumentsAdaption()) {
+ if (dont_adapt_arguments) {
__ Set(rax, arity);
}
// Invoke function.
__ SetCallKind(rcx, call_kind);
- if (*function == *info()->closure()) {
+ if (function.is_identical_to(info()->closure())) {
__ CallSelf();
} else {
__ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
SafepointGenerator generator(
this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(arity);
- __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
+ ParameterCount expected(formal_parameter_count);
+ __ InvokeFunction(
+ function, expected, count, CALL_FUNCTION, generator, call_kind);
}
// Restore context.
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
- CallKnownFunction(instr->function(),
+ CallKnownFunction(instr->hydrogen()->function(),
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_METHOD,
ASSERT(ToRegister(instr->function()).is(rdi));
ASSERT(instr->HasPointerMap());
- if (instr->known_function().is_null()) {
+ Handle<JSFunction> known_function = instr->hydrogen()->known_function();
+ if (known_function.is_null()) {
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
__ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
} else {
- CallKnownFunction(instr->known_function(),
+ CallKnownFunction(known_function,
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_METHOD,
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(rax));
- CallKnownFunction(instr->target(),
+ CallKnownFunction(instr->hydrogen()->target(),
+ instr->hydrogen()->formal_parameter_count(),
instr->arity(),
instr,
CALL_AS_FUNCTION,
void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
Register reg = ToRegister(instr->value());
Handle<JSFunction> target = instr->hydrogen()->target();
+ ALLOW_HANDLE_DEREF(isolate(), "using raw address");
if (isolate()->heap()->InNewSpace(*target)) {
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(target);
Register result = ToRegister(instr->result());
Register scratch = ToRegister(instr->temp());
Handle<JSFunction> constructor = instr->hydrogen()->constructor();
- Handle<Map> initial_map(constructor->initial_map());
+ Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
ASSERT(initial_map->pre_allocated_property_fields() +
initial_map->unused_property_fields() -
initial_map->inobject_properties() == 0);
- // Allocate memory for the object. The initial map might change when
- // the constructor's prototype changes, but instance size and property
- // counts remain unchanged (if slack tracking finished).
- ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
__ Allocate(instance_size, result, no_reg, scratch, deferred->entry(),
TAG_OBJECT);
void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
Register result = ToRegister(instr->result());
- Handle<JSFunction> constructor = instr->hydrogen()->constructor();
- Handle<Map> initial_map(constructor->initial_map());
+ Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
int instance_size = initial_map->instance_size();
// TODO(3095996): Get rid of this. For now, we need to make the
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
- Handle<FixedArray> literals(instr->environment()->closure()->literals());
+ Handle<FixedArray> literals = instr->hydrogen()->literals();
ElementsKind boilerplate_elements_kind =
instr->hydrogen()->boilerplate_elements_kind();
AllocationSiteMode allocation_site_mode =
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
- Handle<FixedArray> literals(instr->environment()->closure()->literals());
+ Handle<FixedArray> literals = instr->hydrogen()->literals();
Handle<FixedArray> constant_properties =
instr->hydrogen()->constant_properties();
// Set up the parameters to the stub/runtime call and pick the right
// runtime function or stub to call.
- int properties_count = constant_properties->length() / 2;
+ int properties_count = instr->hydrogen()->constant_properties_length() / 2;
if (instr->hydrogen()->depth() > 1) {
__ PushHeapObject(literals);
__ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (!pretenure && shared_info->num_literals() == 0) {
- FastNewClosureStub stub(shared_info->language_mode(),
- shared_info->is_generator());
- __ Push(shared_info);
+ if (!pretenure && instr->hydrogen()->has_no_literals()) {
+ FastNewClosureStub stub(instr->hydrogen()->language_mode(),
+ instr->hydrogen()->is_generator());
+ __ Push(instr->hydrogen()->shared_info());
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
} else {
__ push(rsi);
- __ Push(shared_info);
- __ PushRoot(pretenure ?
- Heap::kTrueValueRootIndex :
- Heap::kFalseValueRootIndex);
+ __ Push(instr->hydrogen()->shared_info());
+ __ PushRoot(pretenure ? Heap::kTrueValueRootIndex :
+ Heap::kFalseValueRootIndex);
CallRuntime(Runtime::kNewClosure, 3, instr);
}
}
ASSERT(!operand->IsDoubleRegister());
if (operand->IsConstantOperand()) {
Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (object->IsSmi()) {
__ Push(Handle<Smi>::cast(object));
} else {
// Generate a direct call to a known function. Expects the function
// to be in rdi.
void CallKnownFunction(Handle<JSFunction> function,
+ int formal_parameter_count,
int arity,
LInstruction* instr,
CallKind call_kind,
virtual void PrintDataTo(StringStream* stream);
int arity() const { return hydrogen()->argument_count() - 1; }
- Handle<JSFunction> known_function() { return hydrogen()->known_function(); }
};
virtual void PrintDataTo(StringStream* stream);
- Handle<JSFunction> target() const { return hydrogen()->target(); }
int arity() const { return hydrogen()->argument_count() - 1; }
};
public:
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
-
- Handle<SharedFunctionInfo> shared_info() { return hydrogen()->shared_info(); }
};
void MacroAssembler::Move(Register dst, Handle<Object> source) {
- ASSERT(!source->IsFailure());
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (source->IsSmi()) {
Move(dst, Smi::cast(*source));
} else {
void MacroAssembler::Move(const Operand& dst, Handle<Object> source) {
- ASSERT(!source->IsFailure());
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (source->IsSmi()) {
Move(dst, Smi::cast(*source));
} else {
void MacroAssembler::Cmp(Register dst, Handle<Object> source) {
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (source->IsSmi()) {
Cmp(dst, Smi::cast(*source));
} else {
void MacroAssembler::Cmp(const Operand& dst, Handle<Object> source) {
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (source->IsSmi()) {
Cmp(dst, Smi::cast(*source));
} else {
void MacroAssembler::Push(Handle<Object> source) {
+ ALLOW_HANDLE_DEREF(isolate(), "smi check");
if (source->IsSmi()) {
Push(Smi::cast(*source));
} else {
void MacroAssembler::LoadHeapObject(Register result,
Handle<HeapObject> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "using raw address");
if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(object);
void MacroAssembler::PushHeapObject(Handle<HeapObject> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "using raw address");
if (isolate()->heap()->InNewSpace(*object)) {
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(object);
void MacroAssembler::LoadGlobalCell(Register dst,
Handle<JSGlobalPropertyCell> cell) {
if (dst.is(rax)) {
+ ALLOW_HANDLE_DEREF(isolate(), "embedding raw address");
load_rax(cell.location(), RelocInfo::GLOBAL_PROPERTY_CELL);
} else {
movq(dst, cell, RelocInfo::GLOBAL_PROPERTY_CELL);
void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper,
// allow recompilation to take effect without changing any of the
// call sites.
movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
- ParameterCount expected(function->shared()->formal_parameter_count());
InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind);
}
CallKind call_kind);
void InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper,
void PushHeapObject(Handle<HeapObject> object);
void LoadObject(Register result, Handle<Object> object) {
+ ALLOW_HANDLE_DEREF(isolate(), "heap object check");
if (object->IsHeapObject()) {
LoadHeapObject(result, Handle<HeapObject>::cast(object));
} else {
CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(optimization.constant_function(), arguments_,
+ Handle<JSFunction> fun = optimization.constant_function();
+ __ InvokeFunction(fun, ParameterCount(fun), arguments_,
JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind);
__ bind(&miss);
// rcx: function name.
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind);
__ bind(&miss);
// rcx: function name.
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ __ InvokeFunction(function, ParameterCount(function), arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
__ push(rdx);
__ push(rax);
ParameterCount actual(1);
- __ InvokeFunction(setter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ ParameterCount expected(setter);
+ __ InvokeFunction(setter, expected, actual,
+ CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
} else {
// If we generate a global code snippet for deoptimization only, remember
// the place to continue after deoptimization.
// Call the JavaScript getter with the receiver on the stack.
__ push(rax);
ParameterCount actual(0);
- __ InvokeFunction(getter, actual, CALL_FUNCTION, NullCallWrapper(),
- CALL_AS_METHOD);
+ ParameterCount expected(getter);
+ __ InvokeFunction(getter, expected, actual,
+ CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
} else {
// If we generate a global code snippet for deoptimization only, remember
// the place to continue after deoptimization.