0880d4da26
R=verwaest@chromium.org BUG= Review URL: https://codereview.chromium.org/962613002 Cr-Commit-Position: refs/heads/master@{#27271}
224 lines
7.1 KiB
C++
224 lines
7.1 KiB
C++
// Copyright 2014 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.
|
|
|
|
#ifndef V8_LOOKUP_H_
|
|
#define V8_LOOKUP_H_
|
|
|
|
#include "src/factory.h"
|
|
#include "src/isolate.h"
|
|
#include "src/objects.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
class LookupIterator FINAL BASE_EMBEDDED {
|
|
public:
|
|
enum Configuration {
|
|
// Configuration bits.
|
|
kHidden = 1 << 0,
|
|
kInterceptor = 1 << 1,
|
|
kPrototypeChain = 1 << 2,
|
|
|
|
// Convience combinations of bits.
|
|
OWN_SKIP_INTERCEPTOR = 0,
|
|
OWN = kInterceptor,
|
|
HIDDEN_SKIP_INTERCEPTOR = kHidden,
|
|
HIDDEN = kHidden | kInterceptor,
|
|
PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kHidden | kPrototypeChain,
|
|
PROTOTYPE_CHAIN = kHidden | kPrototypeChain | kInterceptor
|
|
};
|
|
|
|
enum State {
|
|
ACCESS_CHECK,
|
|
INTEGER_INDEXED_EXOTIC,
|
|
INTERCEPTOR,
|
|
JSPROXY,
|
|
NOT_FOUND,
|
|
ACCESSOR,
|
|
DATA,
|
|
TRANSITION,
|
|
// Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
|
|
// PROPERTY lookup.
|
|
BEFORE_PROPERTY = INTERCEPTOR
|
|
};
|
|
|
|
LookupIterator(Handle<Object> receiver, Handle<Name> name,
|
|
Configuration configuration = PROTOTYPE_CHAIN)
|
|
: configuration_(ComputeConfiguration(configuration, name)),
|
|
state_(NOT_FOUND),
|
|
exotic_index_state_(ExoticIndexState::kUninitialized),
|
|
interceptor_state_(InterceptorState::kUninitialized),
|
|
property_details_(PropertyDetails::Empty()),
|
|
isolate_(name->GetIsolate()),
|
|
name_(name),
|
|
receiver_(receiver),
|
|
holder_(GetRoot(receiver_, isolate_)),
|
|
holder_map_(holder_->map(), isolate_),
|
|
initial_holder_(holder_),
|
|
number_(DescriptorArray::kNotFound) {
|
|
Next();
|
|
}
|
|
|
|
LookupIterator(Handle<Object> receiver, Handle<Name> name,
|
|
Handle<JSReceiver> holder,
|
|
Configuration configuration = PROTOTYPE_CHAIN)
|
|
: configuration_(ComputeConfiguration(configuration, name)),
|
|
state_(NOT_FOUND),
|
|
exotic_index_state_(ExoticIndexState::kUninitialized),
|
|
interceptor_state_(InterceptorState::kUninitialized),
|
|
property_details_(PropertyDetails::Empty()),
|
|
isolate_(name->GetIsolate()),
|
|
name_(name),
|
|
receiver_(receiver),
|
|
holder_(holder),
|
|
holder_map_(holder_->map(), isolate_),
|
|
initial_holder_(holder_),
|
|
number_(DescriptorArray::kNotFound) {
|
|
Next();
|
|
}
|
|
|
|
Isolate* isolate() const { return isolate_; }
|
|
State state() const { return state_; }
|
|
Handle<Name> name() const { return name_; }
|
|
|
|
bool IsFound() const { return state_ != NOT_FOUND; }
|
|
void Next();
|
|
void NotFound() {
|
|
has_property_ = false;
|
|
state_ = NOT_FOUND;
|
|
}
|
|
|
|
Factory* factory() const { return isolate_->factory(); }
|
|
Handle<Object> GetReceiver() const { return receiver_; }
|
|
Handle<JSObject> GetStoreTarget() const;
|
|
bool is_dictionary_holder() const { return holder_map_->is_dictionary_map(); }
|
|
Handle<Map> transition_map() const {
|
|
DCHECK_EQ(TRANSITION, state_);
|
|
return Handle<Map>::cast(transition_);
|
|
}
|
|
template <class T>
|
|
Handle<T> GetHolder() const {
|
|
DCHECK(IsFound());
|
|
return Handle<T>::cast(holder_);
|
|
}
|
|
static Handle<JSReceiver> GetRoot(Handle<Object> receiver, Isolate* isolate);
|
|
bool HolderIsReceiverOrHiddenPrototype() const;
|
|
|
|
/* ACCESS_CHECK */
|
|
bool HasAccess() const;
|
|
|
|
/* PROPERTY */
|
|
void PrepareForDataProperty(Handle<Object> value);
|
|
void PrepareTransitionToDataProperty(Handle<Object> value,
|
|
PropertyAttributes attributes,
|
|
Object::StoreFromKeyed store_mode);
|
|
bool IsCacheableTransition() {
|
|
if (state_ != TRANSITION) return false;
|
|
return transition_->IsPropertyCell() ||
|
|
transition_map()->GetBackPointer()->IsMap();
|
|
}
|
|
void ApplyTransitionToDataProperty();
|
|
void ReconfigureDataProperty(Handle<Object> value,
|
|
PropertyAttributes attributes);
|
|
void TransitionToAccessorProperty(AccessorComponent component,
|
|
Handle<Object> accessor,
|
|
PropertyAttributes attributes);
|
|
PropertyDetails property_details() const {
|
|
DCHECK(has_property_);
|
|
return property_details_;
|
|
}
|
|
bool IsConfigurable() const { return property_details().IsConfigurable(); }
|
|
bool IsReadOnly() const { return property_details().IsReadOnly(); }
|
|
Representation representation() const {
|
|
return property_details().representation();
|
|
}
|
|
FieldIndex GetFieldIndex() const;
|
|
Handle<HeapType> GetFieldType() const;
|
|
int GetAccessorIndex() const;
|
|
int GetConstantIndex() const;
|
|
Handle<PropertyCell> GetPropertyCell() const;
|
|
Handle<PropertyCell> GetTransitionPropertyCell() const {
|
|
DCHECK_EQ(TRANSITION, state_);
|
|
return Handle<PropertyCell>::cast(transition_);
|
|
}
|
|
Handle<Object> GetAccessors() const;
|
|
Handle<Object> GetDataValue() const;
|
|
// Usually returns the value that was passed in, but may perform
|
|
// non-observable modifications on it, such as internalize strings.
|
|
Handle<Object> WriteDataValue(Handle<Object> value);
|
|
void InternalizeName();
|
|
|
|
private:
|
|
enum class InterceptorState {
|
|
kUninitialized,
|
|
kSkipNonMasking,
|
|
kProcessNonMasking
|
|
};
|
|
|
|
Handle<Map> GetReceiverMap() const;
|
|
|
|
MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
|
|
inline State LookupInHolder(Map* map, JSReceiver* holder);
|
|
void RestartLookupForNonMaskingInterceptors();
|
|
State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder);
|
|
Handle<Object> FetchValue() const;
|
|
void ReloadPropertyInformation();
|
|
bool SkipInterceptor(JSObject* holder);
|
|
|
|
bool IsBootstrapping() const;
|
|
|
|
bool check_hidden() const { return (configuration_ & kHidden) != 0; }
|
|
bool check_interceptor() const {
|
|
return !IsBootstrapping() && (configuration_ & kInterceptor) != 0;
|
|
}
|
|
bool check_prototype_chain() const {
|
|
return (configuration_ & kPrototypeChain) != 0;
|
|
}
|
|
int descriptor_number() const {
|
|
DCHECK(has_property_);
|
|
DCHECK(!holder_map_->is_dictionary_map());
|
|
return number_;
|
|
}
|
|
int dictionary_entry() const {
|
|
DCHECK(has_property_);
|
|
DCHECK(holder_map_->is_dictionary_map());
|
|
return number_;
|
|
}
|
|
|
|
static Configuration ComputeConfiguration(
|
|
Configuration configuration, Handle<Name> name) {
|
|
if (name->IsOwn()) {
|
|
return static_cast<Configuration>(configuration &
|
|
HIDDEN_SKIP_INTERCEPTOR);
|
|
} else {
|
|
return configuration;
|
|
}
|
|
}
|
|
|
|
enum class ExoticIndexState { kUninitialized, kNoIndex, kIndex };
|
|
bool IsIntegerIndexedExotic(JSReceiver* holder);
|
|
|
|
// If configuration_ becomes mutable, update
|
|
// HolderIsReceiverOrHiddenPrototype.
|
|
const Configuration configuration_;
|
|
State state_;
|
|
bool has_property_;
|
|
ExoticIndexState exotic_index_state_;
|
|
InterceptorState interceptor_state_;
|
|
PropertyDetails property_details_;
|
|
Isolate* const isolate_;
|
|
Handle<Name> name_;
|
|
Handle<Object> transition_;
|
|
const Handle<Object> receiver_;
|
|
Handle<JSReceiver> holder_;
|
|
Handle<Map> holder_map_;
|
|
const Handle<JSReceiver> initial_holder_;
|
|
int number_;
|
|
};
|
|
|
|
|
|
} } // namespace v8::internal
|
|
|
|
#endif // V8_LOOKUP_H_
|