00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "v8.h"
00029
00030 #include "accessors.h"
00031 #include "execution.h"
00032 #include "factory.h"
00033 #include "scopeinfo.h"
00034 #include "top.h"
00035 #include "zone-inl.h"
00036
00037 namespace v8 { namespace internal {
00038
00039
00040 template <class C>
00041 static C* FindInPrototypeChain(Object* obj, bool* found_it) {
00042 ASSERT(!*found_it);
00043 while (!Is<C>(obj)) {
00044 if (obj == Heap::null_value()) return NULL;
00045 obj = obj->GetPrototype();
00046 }
00047 *found_it = true;
00048 return C::cast(obj);
00049 }
00050
00051
00052
00053 Object* Accessors::IllegalSetter(JSObject*, Object*, void*) {
00054 UNREACHABLE();
00055 return NULL;
00056 }
00057
00058
00059 Object* Accessors::IllegalGetAccessor(Object* object, void*) {
00060 UNREACHABLE();
00061 return object;
00062 }
00063
00064
00065 Object* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
00066
00067
00068 return value;
00069 }
00070
00071
00072
00073
00074
00075
00076
00077 Object* Accessors::ArrayGetLength(Object* object, void*) {
00078
00079 bool found_it = false;
00080 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
00081 if (!found_it) return Smi::FromInt(0);
00082 return holder->length();
00083 }
00084
00085
00086
00087 Object* Accessors::FlattenNumber(Object* value) {
00088 if (value->IsNumber() || !value->IsJSValue()) return value;
00089 JSValue* wrapper = JSValue::cast(value);
00090 ASSERT(
00091 Top::context()->global_context()->number_function()->has_initial_map());
00092 Map* number_map =
00093 Top::context()->global_context()->number_function()->initial_map();
00094 if (wrapper->map() == number_map) return wrapper->value();
00095 return value;
00096 }
00097
00098
00099 Object* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
00100 value = FlattenNumber(value);
00101
00102
00103 HandleScope scope;
00104
00105
00106 Handle<JSObject> object_handle(object);
00107 Handle<Object> value_handle(value);
00108
00109 bool has_exception;
00110 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
00111 if (has_exception) return Failure::Exception();
00112 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
00113 if (has_exception) return Failure::Exception();
00114
00115
00116 object = *object_handle;
00117 value = *value_handle;
00118
00119 if (uint32_v->Number() == number_v->Number()) {
00120 if (object->IsJSArray()) {
00121 return JSArray::cast(object)->SetElementsLength(*uint32_v);
00122 } else {
00123
00124
00125
00126 return object->IgnoreAttributesAndSetLocalProperty(Heap::length_symbol(),
00127 value, NONE);
00128 }
00129 }
00130 return Top::Throw(*Factory::NewRangeError("invalid_array_length",
00131 HandleVector<Object>(NULL, 0)));
00132 }
00133
00134
00135 const AccessorDescriptor Accessors::ArrayLength = {
00136 ArrayGetLength,
00137 ArraySetLength,
00138 0
00139 };
00140
00141
00142
00143
00144
00145
00146
00147 Object* Accessors::StringGetLength(Object* object, void*) {
00148 Object* value = object;
00149 if (object->IsJSValue()) value = JSValue::cast(object)->value();
00150 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
00151
00152
00153 return Smi::FromInt(0);
00154 }
00155
00156
00157 const AccessorDescriptor Accessors::StringLength = {
00158 StringGetLength,
00159 IllegalSetter,
00160 0
00161 };
00162
00163
00164
00165
00166
00167
00168
00169 Object* Accessors::ScriptGetSource(Object* object, void*) {
00170 Object* script = JSValue::cast(object)->value();
00171 return Script::cast(script)->source();
00172 }
00173
00174
00175 const AccessorDescriptor Accessors::ScriptSource = {
00176 ScriptGetSource,
00177 IllegalSetter,
00178 0
00179 };
00180
00181
00182
00183
00184
00185
00186
00187 Object* Accessors::ScriptGetName(Object* object, void*) {
00188 Object* script = JSValue::cast(object)->value();
00189 return Script::cast(script)->name();
00190 }
00191
00192
00193 const AccessorDescriptor Accessors::ScriptName = {
00194 ScriptGetName,
00195 IllegalSetter,
00196 0
00197 };
00198
00199
00200
00201
00202
00203
00204
00205 Object* Accessors::ScriptGetLineOffset(Object* object, void*) {
00206 Object* script = JSValue::cast(object)->value();
00207 return Script::cast(script)->line_offset();
00208 }
00209
00210
00211 const AccessorDescriptor Accessors::ScriptLineOffset = {
00212 ScriptGetLineOffset,
00213 IllegalSetter,
00214 0
00215 };
00216
00217
00218
00219
00220
00221
00222
00223 Object* Accessors::ScriptGetColumnOffset(Object* object, void*) {
00224 Object* script = JSValue::cast(object)->value();
00225 return Script::cast(script)->column_offset();
00226 }
00227
00228
00229 const AccessorDescriptor Accessors::ScriptColumnOffset = {
00230 ScriptGetColumnOffset,
00231 IllegalSetter,
00232 0
00233 };
00234
00235
00236
00237
00238
00239
00240
00241 Object* Accessors::ScriptGetType(Object* object, void*) {
00242 Object* script = JSValue::cast(object)->value();
00243 return Script::cast(script)->type();
00244 }
00245
00246
00247 const AccessorDescriptor Accessors::ScriptType = {
00248 ScriptGetType,
00249 IllegalSetter,
00250 0
00251 };
00252
00253
00254
00255
00256
00257
00258
00259 Object* Accessors::FunctionGetPrototype(Object* object, void*) {
00260 bool found_it = false;
00261 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
00262 if (!found_it) return Heap::undefined_value();
00263 if (!function->has_prototype()) {
00264 Object* prototype = Heap::AllocateFunctionPrototype(function);
00265 if (prototype->IsFailure()) return prototype;
00266 Object* result = function->SetPrototype(prototype);
00267 if (result->IsFailure()) return result;
00268 }
00269 return function->prototype();
00270 }
00271
00272
00273 Object* Accessors::FunctionSetPrototype(JSObject* object,
00274 Object* value,
00275 void*) {
00276 bool found_it = false;
00277 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
00278 if (!found_it) return Heap::undefined_value();
00279 if (function->has_initial_map()) {
00280
00281
00282 Object* new_map = function->initial_map()->CopyDropTransitions();
00283 if (new_map->IsFailure()) return new_map;
00284 function->set_initial_map(Map::cast(new_map));
00285 }
00286 Object* prototype = function->SetPrototype(value);
00287 if (prototype->IsFailure()) return prototype;
00288 ASSERT(function->prototype() == value);
00289 return function;
00290 }
00291
00292
00293 const AccessorDescriptor Accessors::FunctionPrototype = {
00294 FunctionGetPrototype,
00295 FunctionSetPrototype,
00296 0
00297 };
00298
00299
00300
00301
00302
00303
00304
00305 Object* Accessors::FunctionGetLength(Object* object, void*) {
00306 bool found_it = false;
00307 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
00308 if (!found_it) return Smi::FromInt(0);
00309
00310 if (!function->is_compiled()) {
00311
00312
00313 HandleScope scope;
00314 Handle<JSFunction> function_handle(function);
00315 if (!CompileLazy(function_handle, KEEP_EXCEPTION)) {
00316 return Failure::Exception();
00317 }
00318 return Smi::FromInt(function_handle->shared()->length());
00319 } else {
00320 return Smi::FromInt(function->shared()->length());
00321 }
00322 }
00323
00324
00325 const AccessorDescriptor Accessors::FunctionLength = {
00326 FunctionGetLength,
00327 ReadOnlySetAccessor,
00328 0
00329 };
00330
00331
00332
00333
00334
00335
00336
00337 Object* Accessors::FunctionGetName(Object* object, void*) {
00338 bool found_it = false;
00339 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
00340 if (!found_it) return Heap::undefined_value();
00341 return holder->shared()->name();
00342 }
00343
00344
00345 const AccessorDescriptor Accessors::FunctionName = {
00346 FunctionGetName,
00347 ReadOnlySetAccessor,
00348 0
00349 };
00350
00351
00352
00353
00354
00355
00356
00357 Object* Accessors::FunctionGetArguments(Object* object, void*) {
00358 HandleScope scope;
00359 bool found_it = false;
00360 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
00361 if (!found_it) return Heap::undefined_value();
00362 Handle<JSFunction> function(holder);
00363
00364
00365 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
00366
00367 JavaScriptFrame* frame = it.frame();
00368 if (frame->function() != *function) continue;
00369
00370
00371 int index = ScopeInfo<>::StackSlotIndex(frame->FindCode(),
00372 Heap::arguments_symbol());
00373 if (index >= 0) return frame->GetExpression(index);
00374
00375
00376
00377
00378 it.AdvanceToArgumentsFrame();
00379 frame = it.frame();
00380
00381
00382
00383 const int length = frame->GetProvidedParametersCount();
00384 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
00385 Handle<FixedArray> array = Factory::NewFixedArray(length);
00386
00387
00388 ASSERT(array->length() == length);
00389 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
00390 arguments->set_elements(*array);
00391
00392
00393 return *arguments;
00394 }
00395
00396
00397 return Heap::null_value();
00398 }
00399
00400
00401 const AccessorDescriptor Accessors::FunctionArguments = {
00402 FunctionGetArguments,
00403 ReadOnlySetAccessor,
00404 0
00405 };
00406
00407
00408
00409
00410
00411
00412
00413 Object* Accessors::FunctionGetCaller(Object* object, void*) {
00414 HandleScope scope;
00415 bool found_it = false;
00416 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
00417 if (!found_it) return Heap::undefined_value();
00418 Handle<JSFunction> function(holder);
00419
00420
00421 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
00422
00423 if (it.frame()->function() != *function) continue;
00424
00425
00426
00427 while (true) {
00428 it.Advance();
00429 if (it.done()) return Heap::null_value();
00430 JSFunction* caller = JSFunction::cast(it.frame()->function());
00431 if (!caller->shared()->is_toplevel()) return caller;
00432 }
00433 }
00434
00435
00436 return Heap::null_value();
00437 }
00438
00439
00440 const AccessorDescriptor Accessors::FunctionCaller = {
00441 FunctionGetCaller,
00442 ReadOnlySetAccessor,
00443 0
00444 };
00445
00446
00447
00448
00449
00450
00451
00452 Object* Accessors::ObjectGetPrototype(Object* receiver, void*) {
00453 Object* current = receiver->GetPrototype();
00454 while (current->IsJSObject() &&
00455 JSObject::cast(current)->map()->is_hidden_prototype()) {
00456 current = current->GetPrototype();
00457 }
00458 return current;
00459 }
00460
00461
00462 Object* Accessors::ObjectSetPrototype(JSObject* receiver,
00463 Object* value,
00464 void*) {
00465
00466
00467
00468
00469
00470
00471
00472 if (!value->IsJSObject() && !value->IsNull()) return value;
00473
00474 for (Object* pt = value; pt != Heap::null_value(); pt = pt->GetPrototype()) {
00475 if (JSObject::cast(pt) == receiver) {
00476
00477 HandleScope scope;
00478 return Top::Throw(*Factory::NewError("cyclic_proto",
00479 HandleVector<Object>(NULL, 0)));
00480 }
00481 }
00482
00483
00484
00485 JSObject* current = receiver;
00486 Object* current_proto = receiver->GetPrototype();
00487 while (current_proto->IsJSObject() &&
00488 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
00489 current = JSObject::cast(current_proto);
00490 current_proto = current_proto->GetPrototype();
00491 }
00492
00493
00494 Object* new_map = current->map()->CopyDropTransitions();
00495 if (new_map->IsFailure()) return new_map;
00496 Map::cast(new_map)->set_prototype(value);
00497 current->set_map(Map::cast(new_map));
00498
00499
00500 return value;
00501 }
00502
00503
00504 const AccessorDescriptor Accessors::ObjectPrototype = {
00505 ObjectGetPrototype,
00506 ObjectSetPrototype,
00507 0
00508 };
00509
00510 } }