blob: a43eb78b8702d57ca504e734a38e1bc635582bec [file] [log] [blame]
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000029#include "accessors.h"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000030
31#include "contexts.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "execution.h"
34#include "factory.h"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000035#include "frames-inl.h"
36#include "isolate.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000037#include "list-inl.h"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000038#include "property-details.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
43
44template <class C>
hpayer@chromium.org8432c912013-02-28 15:55:26 +000045static C* FindInstanceOf(Isolate* isolate, Object* obj) {
46 for (Object* cur = obj; !cur->IsNull(); cur = cur->GetPrototype(isolate)) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000047 if (Is<C>(cur)) return C::cast(cur);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000049 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050}
51
52
53// Entry point that never should be called.
lrn@chromium.org303ada72010-10-27 09:33:13 +000054MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055 UNREACHABLE();
56 return NULL;
57}
58
59
60Object* Accessors::IllegalGetAccessor(Object* object, void*) {
61 UNREACHABLE();
62 return object;
63}
64
65
lrn@chromium.org303ada72010-10-27 09:33:13 +000066MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067 // According to ECMA-262, section 8.6.2.2, page 28, setting
68 // read-only properties must be silently ignored.
69 return value;
70}
71
72
73//
74// Accessors::ArrayLength
75//
76
77
lrn@chromium.org303ada72010-10-27 09:33:13 +000078MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 // Traverse the prototype chain until we reach an array.
hpayer@chromium.org8432c912013-02-28 15:55:26 +000080 JSArray* holder = FindInstanceOf<JSArray>(Isolate::Current(), object);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000081 return holder == NULL ? Smi::FromInt(0) : holder->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082}
83
84
85// The helper function will 'flatten' Number objects.
86Object* Accessors::FlattenNumber(Object* value) {
87 if (value->IsNumber() || !value->IsJSValue()) return value;
88 JSValue* wrapper = JSValue::cast(value);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000089 ASSERT(Isolate::Current()->context()->native_context()->number_function()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000090 has_initial_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000091 Map* number_map = Isolate::Current()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000092 number_function()->initial_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093 if (wrapper->map() == number_map) return wrapper->value();
94 return value;
95}
96
97
lrn@chromium.org303ada72010-10-27 09:33:13 +000098MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +000099 Isolate* isolate = object->GetIsolate();
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000100
101 // This means one of the object's prototypes is a JSArray and the
102 // object does not have a 'length' property. Calling SetProperty
103 // causes an infinite loop.
104 if (!object->IsJSArray()) {
105 return object->SetLocalPropertyIgnoreAttributes(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000106 isolate->heap()->length_string(), value, NONE);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000107 }
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109 value = FlattenNumber(value);
110
111 // Need to call methods that may trigger GC.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000112 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113
114 // Protect raw pointers.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000115 Handle<JSArray> array_handle(JSArray::cast(object), isolate);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000116 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117
118 bool has_exception;
119 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
120 if (has_exception) return Failure::Exception();
121 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
122 if (has_exception) return Failure::Exception();
123
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 if (uint32_v->Number() == number_v->Number()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000125 return array_handle->SetElementsLength(*uint32_v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000127 return isolate->Throw(
128 *isolate->factory()->NewRangeError("invalid_array_length",
129 HandleVector<Object>(NULL, 0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130}
131
132
133const AccessorDescriptor Accessors::ArrayLength = {
134 ArrayGetLength,
135 ArraySetLength,
136 0
137};
138
139
140//
141// Accessors::StringLength
142//
143
144
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145MaybeObject* Accessors::StringGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 Object* value = object;
147 if (object->IsJSValue()) value = JSValue::cast(object)->value();
148 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
149 // If object is not a string we return 0 to be compatible with WebKit.
150 // Note: Firefox returns the length of ToString(object).
151 return Smi::FromInt(0);
152}
153
154
155const AccessorDescriptor Accessors::StringLength = {
156 StringGetLength,
157 IllegalSetter,
158 0
159};
160
161
162//
163// Accessors::ScriptSource
164//
165
166
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168 Object* script = JSValue::cast(object)->value();
169 return Script::cast(script)->source();
170}
171
172
173const AccessorDescriptor Accessors::ScriptSource = {
174 ScriptGetSource,
175 IllegalSetter,
176 0
177};
178
179
180//
181// Accessors::ScriptName
182//
183
184
lrn@chromium.org303ada72010-10-27 09:33:13 +0000185MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186 Object* script = JSValue::cast(object)->value();
187 return Script::cast(script)->name();
188}
189
190
191const AccessorDescriptor Accessors::ScriptName = {
192 ScriptGetName,
193 IllegalSetter,
194 0
195};
196
197
198//
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000199// Accessors::ScriptId
200//
201
202
lrn@chromium.org303ada72010-10-27 09:33:13 +0000203MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000204 Object* script = JSValue::cast(object)->value();
205 return Script::cast(script)->id();
206}
207
208
209const AccessorDescriptor Accessors::ScriptId = {
210 ScriptGetId,
211 IllegalSetter,
212 0
213};
214
215
216//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217// Accessors::ScriptLineOffset
218//
219
220
lrn@chromium.org303ada72010-10-27 09:33:13 +0000221MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 Object* script = JSValue::cast(object)->value();
223 return Script::cast(script)->line_offset();
224}
225
226
227const AccessorDescriptor Accessors::ScriptLineOffset = {
228 ScriptGetLineOffset,
229 IllegalSetter,
230 0
231};
232
233
234//
235// Accessors::ScriptColumnOffset
236//
237
238
lrn@chromium.org303ada72010-10-27 09:33:13 +0000239MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 Object* script = JSValue::cast(object)->value();
241 return Script::cast(script)->column_offset();
242}
243
244
245const AccessorDescriptor Accessors::ScriptColumnOffset = {
246 ScriptGetColumnOffset,
247 IllegalSetter,
248 0
249};
250
251
252//
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000253// Accessors::ScriptData
254//
255
256
lrn@chromium.org303ada72010-10-27 09:33:13 +0000257MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000258 Object* script = JSValue::cast(object)->value();
259 return Script::cast(script)->data();
260}
261
262
263const AccessorDescriptor Accessors::ScriptData = {
264 ScriptGetData,
265 IllegalSetter,
266 0
267};
268
269
270//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000271// Accessors::ScriptType
272//
273
274
lrn@chromium.org303ada72010-10-27 09:33:13 +0000275MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276 Object* script = JSValue::cast(object)->value();
277 return Script::cast(script)->type();
278}
279
280
281const AccessorDescriptor Accessors::ScriptType = {
282 ScriptGetType,
283 IllegalSetter,
284 0
285};
286
287
288//
ager@chromium.orge2902be2009-06-08 12:21:35 +0000289// Accessors::ScriptCompilationType
290//
291
292
lrn@chromium.org303ada72010-10-27 09:33:13 +0000293MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000294 Object* script = JSValue::cast(object)->value();
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000295 return Smi::FromInt(Script::cast(script)->compilation_type());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000296}
297
298
299const AccessorDescriptor Accessors::ScriptCompilationType = {
300 ScriptGetCompilationType,
301 IllegalSetter,
302 0
303};
304
305
306//
iposva@chromium.org245aa852009-02-10 00:49:54 +0000307// Accessors::ScriptGetLineEnds
308//
309
310
lrn@chromium.org303ada72010-10-27 09:33:13 +0000311MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000312 JSValue* wrapper = JSValue::cast(object);
313 Isolate* isolate = wrapper->GetIsolate();
314 HandleScope scope(isolate);
315 Handle<Script> script(Script::cast(wrapper->value()), isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000316 InitScriptLineEnds(script);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000317 ASSERT(script->line_ends()->IsFixedArray());
318 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000319 // We do not want anyone to modify this array from JS.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000320 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
321 line_ends->map() == isolate->heap()->fixed_cow_array_map());
322 Handle<JSArray> js_array =
323 isolate->factory()->NewJSArrayWithElements(line_ends);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000324 return *js_array;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000325}
326
327
328const AccessorDescriptor Accessors::ScriptLineEnds = {
329 ScriptGetLineEnds,
330 IllegalSetter,
331 0
332};
333
334
335//
ager@chromium.org9085a012009-05-11 19:22:57 +0000336// Accessors::ScriptGetContextData
337//
338
339
lrn@chromium.org303ada72010-10-27 09:33:13 +0000340MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000341 Object* script = JSValue::cast(object)->value();
342 return Script::cast(script)->context_data();
ager@chromium.org9085a012009-05-11 19:22:57 +0000343}
344
345
346const AccessorDescriptor Accessors::ScriptContextData = {
347 ScriptGetContextData,
348 IllegalSetter,
349 0
350};
351
352
353//
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000354// Accessors::ScriptGetEvalFromScript
ager@chromium.orge2902be2009-06-08 12:21:35 +0000355//
356
357
lrn@chromium.org303ada72010-10-27 09:33:13 +0000358MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000359 Object* script = JSValue::cast(object)->value();
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000360 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
361 Handle<SharedFunctionInfo> eval_from_shared(
362 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
363
364 if (eval_from_shared->script()->IsScript()) {
365 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
366 return *GetScriptWrapper(eval_from_script);
367 }
368 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000369 return HEAP->undefined_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +0000370}
371
372
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000373const AccessorDescriptor Accessors::ScriptEvalFromScript = {
374 ScriptGetEvalFromScript,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000375 IllegalSetter,
376 0
377};
378
379
380//
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000381// Accessors::ScriptGetEvalFromScriptPosition
ager@chromium.orge2902be2009-06-08 12:21:35 +0000382//
383
384
lrn@chromium.org303ada72010-10-27 09:33:13 +0000385MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000386 Script* raw_script = Script::cast(JSValue::cast(object)->value());
387 HandleScope scope(raw_script->GetIsolate());
388 Handle<Script> script(raw_script);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000389
390 // If this is not a script compiled through eval there is no eval position.
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000391 if (script->compilation_type() != Script::COMPILATION_TYPE_EVAL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000392 return script->GetHeap()->undefined_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +0000393 }
394
395 // Get the function from where eval was called and find the source position
396 // from the instruction offset.
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000397 Handle<Code> code(SharedFunctionInfo::cast(
398 script->eval_from_shared())->code());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000399 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
400 script->eval_from_instructions_offset()->value()));
401}
402
403
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000404const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
405 ScriptGetEvalFromScriptPosition,
406 IllegalSetter,
407 0
408};
409
410
411//
412// Accessors::ScriptGetEvalFromFunctionName
413//
414
415
lrn@chromium.org303ada72010-10-27 09:33:13 +0000416MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000417 Object* script = JSValue::cast(object)->value();
418 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
419 Script::cast(script)->eval_from_shared()));
420
421
422 // Find the name of the function calling eval.
423 if (!shared->name()->IsUndefined()) {
424 return shared->name();
425 } else {
426 return shared->inferred_name();
427 }
428}
429
430
431const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
432 ScriptGetEvalFromFunctionName,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000433 IllegalSetter,
434 0
435};
436
437
438//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439// Accessors::FunctionPrototype
440//
441
442
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000443Handle<Object> Accessors::FunctionGetPrototype(Handle<Object> object) {
444 Isolate* isolate = Isolate::Current();
445 CALL_HEAP_FUNCTION(
446 isolate, Accessors::FunctionGetPrototype(*object, 0), Object);
447}
448
449
lrn@chromium.org303ada72010-10-27 09:33:13 +0000450MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000451 Isolate* isolate = Isolate::Current();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000452 JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object);
453 if (function_raw == NULL) return isolate->heap()->undefined_value();
454 while (!function_raw->should_have_prototype()) {
455 function_raw = FindInstanceOf<JSFunction>(isolate,
456 function_raw->GetPrototype());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000457 // There has to be one because we hit the getter.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000458 ASSERT(function_raw != NULL);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000459 }
460
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000461 if (!function_raw->has_prototype()) {
462 HandleScope scope(isolate);
463 Handle<JSFunction> function(function_raw);
464 Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
465 JSFunction::SetPrototype(function, proto);
466 function_raw = *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000468 return function_raw->prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000469}
470
471
lrn@chromium.org303ada72010-10-27 09:33:13 +0000472MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000473 Object* value_raw,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000474 void*) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000475 Isolate* isolate = object->GetIsolate();
476 Heap* heap = isolate->heap();
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000477 JSFunction* function_raw = FindInstanceOf<JSFunction>(isolate, object);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000478 if (function_raw == NULL) return heap->undefined_value();
479 if (!function_raw->should_have_prototype()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000480 // Since we hit this accessor, object will have no prototype property.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000481 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_string(),
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000482 value_raw,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000483 NONE);
484 }
485
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000486 HandleScope scope(isolate);
487 Handle<JSFunction> function(function_raw, isolate);
488 Handle<Object> value(value_raw, isolate);
489
490 Handle<Object> old_value;
491 bool is_observed =
492 FLAG_harmony_observation &&
493 *function == object &&
494 function->map()->is_observed();
495 if (is_observed) {
496 if (function->has_prototype())
497 old_value = handle(function->prototype(), isolate);
498 else
499 old_value = isolate->factory()->NewFunctionPrototype(function);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000500 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000501
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000502 JSFunction::SetPrototype(function, value);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000503 ASSERT(function->prototype() == *value);
504
505 if (is_observed && !old_value->SameValue(*value)) {
506 JSObject::EnqueueChangeRecord(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000507 function, "updated", isolate->factory()->prototype_string(), old_value);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000508 }
509
510 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511}
512
513
514const AccessorDescriptor Accessors::FunctionPrototype = {
515 FunctionGetPrototype,
516 FunctionSetPrototype,
517 0
518};
519
520
521//
522// Accessors::FunctionLength
523//
524
525
lrn@chromium.org303ada72010-10-27 09:33:13 +0000526MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000527 Isolate* isolate = Isolate::Current();
528 JSFunction* function = FindInstanceOf<JSFunction>(isolate, object);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000529 if (function == NULL) return Smi::FromInt(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530 // Check if already compiled.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000531 if (function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532 return Smi::FromInt(function->shared()->length());
533 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000534 // If the function isn't compiled yet, the length is not computed correctly
535 // yet. Compile it now and return the right length.
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000536 HandleScope scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000537 Handle<JSFunction> handle(function);
538 if (JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
539 return Smi::FromInt(handle->shared()->length());
540 }
541 return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542}
543
544
545const AccessorDescriptor Accessors::FunctionLength = {
546 FunctionGetLength,
547 ReadOnlySetAccessor,
548 0
549};
550
551
552//
553// Accessors::FunctionName
554//
555
556
lrn@chromium.org303ada72010-10-27 09:33:13 +0000557MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000558 Isolate* isolate = Isolate::Current();
559 JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object);
560 return holder == NULL
561 ? isolate->heap()->undefined_value()
562 : holder->shared()->name();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563}
564
565
566const AccessorDescriptor Accessors::FunctionName = {
567 FunctionGetName,
568 ReadOnlySetAccessor,
569 0
570};
571
572
573//
574// Accessors::FunctionArguments
575//
576
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000577
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000578Handle<Object> Accessors::FunctionGetArguments(Handle<Object> object) {
579 Isolate* isolate = Isolate::Current();
580 CALL_HEAP_FUNCTION(
581 isolate, Accessors::FunctionGetArguments(*object, 0), Object);
582}
583
584
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000585static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
586 JavaScriptFrame* frame,
587 Handle<JSFunction> inlined_function,
588 int inlined_frame_index) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000589 Isolate* isolate = inlined_function->GetIsolate();
590 Factory* factory = isolate->factory();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000591 Vector<SlotRef> args_slots =
592 SlotRef::ComputeSlotMappingForArguments(
593 frame,
594 inlined_frame_index,
595 inlined_function->shared()->formal_parameter_count());
596 int args_count = args_slots.length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000597 Handle<JSObject> arguments =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 factory->NewArgumentsObject(inlined_function, args_count);
599 Handle<FixedArray> array = factory->NewFixedArray(args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000600 for (int i = 0; i < args_count; ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000601 Handle<Object> value = args_slots[i].GetValue(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000602 array->set(i, *value);
603 }
604 arguments->set_elements(*array);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000605 args_slots.Dispose();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000606
607 // Return the freshly allocated arguments object.
608 return *arguments;
609}
610
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611
lrn@chromium.org303ada72010-10-27 09:33:13 +0000612MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 Isolate* isolate = Isolate::Current();
614 HandleScope scope(isolate);
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000615 JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000616 if (holder == NULL) return isolate->heap()->undefined_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000617 Handle<JSFunction> function(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000619 if (function->shared()->native()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 // Find the top invocation of the function by traversing frames.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621 List<JSFunction*> functions(2);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000622 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 JavaScriptFrame* frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000624 frame->GetFunctions(&functions);
625 for (int i = functions.length() - 1; i >= 0; i--) {
626 // Skip all frames that aren't invocations of the given function.
627 if (functions[i] != *function) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000629 if (i > 0) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000630 // The function in question was inlined. Inlined functions have the
631 // correct number of arguments and no allocated arguments object, so
632 // we can construct a fresh one by interpreting the function's
633 // deoptimization input data.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000634 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000635 }
636
637 if (!frame->is_optimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000638 // If there is an arguments variable in the stack, we return that.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000639 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
640 int index = scope_info->StackSlotIndex(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000641 isolate->heap()->arguments_string());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000642 if (index >= 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 Handle<Object> arguments(frame->GetExpression(index), isolate);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000644 if (!arguments->IsArgumentsMarker()) return *arguments;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000645 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000647
648 // If there is no arguments variable in the stack or we have an
649 // optimized frame, we find the frame that holds the actual arguments
650 // passed to the function.
651 it.AdvanceToArgumentsFrame();
652 frame = it.frame();
653
654 // Get the number of arguments and construct an arguments object
655 // mirror for the right frame.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000656 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
658 function, length);
659 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000660
661 // Copy the parameters to the arguments object.
662 ASSERT(array->length() == length);
663 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
664 arguments->set_elements(*array);
665
666 // Return the freshly allocated arguments object.
667 return *arguments;
ager@chromium.org3e875802009-06-29 08:26:34 +0000668 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000669 functions.Rewind(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670 }
671
672 // No frame corresponding to the given function found. Return null.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000673 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674}
675
676
677const AccessorDescriptor Accessors::FunctionArguments = {
678 FunctionGetArguments,
679 ReadOnlySetAccessor,
680 0
681};
682
683
684//
685// Accessors::FunctionCaller
686//
687
688
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000689class FrameFunctionIterator {
690 public:
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000691 FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise)
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000692 : frame_iterator_(isolate),
693 functions_(2),
694 index_(0) {
695 GetFunctions();
696 }
697 JSFunction* next() {
698 if (functions_.length() == 0) return NULL;
699 JSFunction* next_function = functions_[index_];
700 index_--;
701 if (index_ < 0) {
702 GetFunctions();
703 }
704 return next_function;
705 }
706
707 // Iterate through functions until the first occurence of 'function'.
708 // Returns true if 'function' is found, and false if the iterator ends
709 // without finding it.
710 bool Find(JSFunction* function) {
711 JSFunction* next_function;
712 do {
713 next_function = next();
714 if (next_function == function) return true;
715 } while (next_function != NULL);
716 return false;
717 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000718
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000719 private:
720 void GetFunctions() {
721 functions_.Rewind(0);
722 if (frame_iterator_.done()) return;
723 JavaScriptFrame* frame = frame_iterator_.frame();
724 frame->GetFunctions(&functions_);
725 ASSERT(functions_.length() > 0);
726 frame_iterator_.Advance();
727 index_ = functions_.length() - 1;
728 }
729 JavaScriptFrameIterator frame_iterator_;
730 List<JSFunction*> functions_;
731 int index_;
732};
733
734
lrn@chromium.org303ada72010-10-27 09:33:13 +0000735MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 Isolate* isolate = Isolate::Current();
737 HandleScope scope(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000738 DisallowHeapAllocation no_allocation;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000739 JSFunction* holder = FindInstanceOf<JSFunction>(isolate, object);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000740 if (holder == NULL) return isolate->heap()->undefined_value();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000741 if (holder->shared()->native()) return isolate->heap()->null_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000742 Handle<JSFunction> function(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000744 FrameFunctionIterator it(isolate, no_allocation);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000745
746 // Find the function from the frames.
747 if (!it.Find(*function)) {
748 // No frame corresponding to the given function found. Return null.
749 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750 }
751
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000752 // Find previously called non-toplevel function.
753 JSFunction* caller;
754 do {
755 caller = it.next();
756 if (caller == NULL) return isolate->heap()->null_value();
757 } while (caller->shared()->is_toplevel());
758
759 // If caller is a built-in function and caller's caller is also built-in,
760 // use that instead.
761 JSFunction* potential_caller = caller;
762 while (potential_caller != NULL && potential_caller->IsBuiltin()) {
763 caller = potential_caller;
764 potential_caller = it.next();
765 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000766 if (!caller->shared()->native() && potential_caller != NULL) {
767 caller = potential_caller;
768 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000769 // If caller is bound, return null. This is compatible with JSC, and
770 // allows us to make bound functions use the strict function map
771 // and its associated throwing caller and arguments.
772 if (caller->shared()->bound()) {
773 return isolate->heap()->null_value();
774 }
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000775 // Censor if the caller is not a classic mode function.
776 // Change from ES5, which used to throw, see:
777 // https://bugs.ecmascript.org/show_bug.cgi?id=310
778 if (!caller->shared()->is_classic_mode()) {
779 return isolate->heap()->null_value();
780 }
781
782 return caller;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783}
784
785
786const AccessorDescriptor Accessors::FunctionCaller = {
787 FunctionGetCaller,
788 ReadOnlySetAccessor,
789 0
790};
791
792
793//
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000794// Accessors::MakeModuleExport
795//
796
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000797static void ModuleGetExport(
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000798 v8::Local<v8::String> property,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000799 const v8::PropertyCallbackInfo<v8::Value>& info) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000800 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
801 Context* context = Context::cast(instance->context());
802 ASSERT(context->IsModuleContext());
803 int slot = info.Data()->Int32Value();
804 Object* value = context->get(slot);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000805 Isolate* isolate = instance->GetIsolate();
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000806 if (value->IsTheHole()) {
807 Handle<String> name = v8::Utils::OpenHandle(*property);
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000808 isolate->ScheduleThrow(
809 *isolate->factory()->NewReferenceError("not_defined",
810 HandleVector(&name, 1)));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000811 return;
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000812 }
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000813 info.GetReturnValue().Set(v8::Utils::ToLocal(Handle<Object>(value, isolate)));
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000814}
815
816
817static void ModuleSetExport(
818 v8::Local<v8::String> property,
819 v8::Local<v8::Value> value,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000820 const v8::PropertyCallbackInfo<v8::Value>& info) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000821 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
822 Context* context = Context::cast(instance->context());
823 ASSERT(context->IsModuleContext());
824 int slot = info.Data()->Int32Value();
825 Object* old_value = context->get(slot);
826 if (old_value->IsTheHole()) {
827 Handle<String> name = v8::Utils::OpenHandle(*property);
828 Isolate* isolate = instance->GetIsolate();
829 isolate->ScheduleThrow(
830 *isolate->factory()->NewReferenceError("not_defined",
831 HandleVector(&name, 1)));
832 return;
833 }
834 context->set(slot, *v8::Utils::OpenHandle(*value));
835}
836
837
838Handle<AccessorInfo> Accessors::MakeModuleExport(
839 Handle<String> name,
840 int index,
841 PropertyAttributes attributes) {
842 Factory* factory = name->GetIsolate()->factory();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000843 Handle<ExecutableAccessorInfo> info = factory->NewExecutableAccessorInfo();
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000844 info->set_property_attributes(attributes);
845 info->set_all_can_read(true);
846 info->set_all_can_write(true);
847 info->set_name(*name);
848 info->set_data(Smi::FromInt(index));
849 Handle<Object> getter = v8::FromCData(&ModuleGetExport);
850 Handle<Object> setter = v8::FromCData(&ModuleSetExport);
851 info->set_getter(*getter);
852 if (!(attributes & ReadOnly)) info->set_setter(*setter);
853 return info;
854}
855
856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857} } // namespace v8::internal