blob: d8da56ced5a4bc7c9f6e9b2f23226f3f5e1bc155 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +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 <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000048#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000050#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000051#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000054#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000057#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000059#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000060#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
kasperl@chromium.org71affb52009-05-26 05:44:31 +000063namespace v8 {
64namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
ager@chromium.org3e875802009-06-29 08:26:34 +000067#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Handle<Type> name = args.at<Type>(index);
80
kasper.lundbd3ec4e2008-07-09 11:06:54 +000081// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 }
163 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000172 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000208 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000212 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000233 elements->set(i, result);
234 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235 }
236 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000247 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000259 UNIMPLEMENTED();
260 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 }
274 return copy;
275}
276
277
ager@chromium.org236ad962008-09-25 09:45:57 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000281 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000316 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000318 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000327}
328
329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000335
336static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 bool should_have_fast_elements,
341 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000363
364 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435}
436
437
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
472
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
478 } else {
479 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000487 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000519 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000520 }
521 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000524
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000544 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000569 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 should_have_fast_elements,
584 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000595 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602
603 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 should_have_fast_elements,
610 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000616}
617
618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000625
626 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645
646 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000980 return false;
981 }
982
983 return true;
984}
985
986
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001013
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001052 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001055 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001056 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001057 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001058 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001068 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 break;
1074 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001079 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001082 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 }
1093 }
1094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001096 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001101
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 }
1105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001110 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001115
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001118 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001122 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001126
1127 PropertyAttributes attrs;
1128 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001136 return *desc;
1137}
1138
1139
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001292 bool is_var = value->IsUndefined();
1293 bool is_const = value->IsTheHole();
1294 bool is_function = value->IsSharedFunctionInfo();
1295 bool is_module = value->IsJSModule();
1296 ASSERT(is_var + is_const + is_function + is_module == 1);
1297
1298 if (is_var || is_const) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299 // Lookup the property in the global object, and don't set the
1300 // value of the variable if the property is already there.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001301 // Do the lookup locally only, see ES5 errata.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001302 LookupResult lookup(isolate);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001303 global->LocalLookup(*name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 // We found an existing property. Unless it was an interceptor
1306 // that claims the property is absent, skip this declaration.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001307 if (lookup.type() != INTERCEPTOR) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001308 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001309 if (attributes != ABSENT) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001310 // Fall-through and introduce the absent property by using
1311 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001313 } else if (is_function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Handle<JSFunction> function =
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(
1319 shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 value = function;
1321 }
1322
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001323 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 global->LocalLookup(*name, &lookup);
1325
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001326 // Compute the property attributes. According to ECMA-262,
1327 // the property must be non-configurable except in eval.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001328 int attr = NONE;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001329 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
1330 if (!is_eval || is_module) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001331 attr |= DONT_DELETE;
1332 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001333 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001334 if (is_const || is_module || (is_native && is_function)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001335 attr |= READ_ONLY;
1336 }
1337
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001338 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1339
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001340 if (!lookup.IsProperty() || is_function || is_module) {
1341 // If the local property exists, check that we can reconfigure it
1342 // as required for function declarations.
1343 if (lookup.IsProperty() && lookup.IsDontDelete()) {
1344 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
1345 lookup.type() == CALLBACKS) {
1346 return ThrowRedeclarationError(
1347 isolate, is_function ? "function" : "module", name);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001348 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001349 // If the existing property is not configurable, keep its attributes.
1350 attr = lookup.GetAttributes();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001351 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001352 // Define or redefine own property.
1353 RETURN_IF_EMPTY_HANDLE(isolate,
1354 JSObject::SetLocalPropertyIgnoreAttributes(
1355 global, name, value, static_cast<PropertyAttributes>(attr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001357 // Do a [[Put]] on the existing (own) property.
1358 RETURN_IF_EMPTY_HANDLE(isolate,
1359 JSObject::SetProperty(
1360 global, name, value, static_cast<PropertyAttributes>(attr),
1361 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362 }
1363 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001365 ASSERT(!isolate->has_pending_exception());
1366 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367}
1368
1369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001370RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001371 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001374 // Declarations are always made in a function or global context. In the
1375 // case of eval code, the context passed is the context of the caller,
1376 // which may be some nested context and not the declaration context.
1377 RUNTIME_ASSERT(args[0]->IsContext());
1378 Handle<Context> context(Context::cast(args[0])->declaration_context());
1379
ager@chromium.org7c537e22008-10-16 08:43:32 +00001380 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001381 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001382 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 int index;
1386 PropertyAttributes attributes;
1387 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001388 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001389 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001390 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391
1392 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001393 // The name was declared before; check for conflicting re-declarations.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001394 // Note: this is actually inconsistent with what happens for globals (where
1395 // we silently ignore such declarations).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1397 // Functions are not read-only.
1398 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1399 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001401 }
1402
1403 // Initialize it if necessary.
1404 if (*initial_value != NULL) {
1405 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001406 ASSERT(holder.is_identical_to(context));
1407 if (((attributes & READ_ONLY) == 0) ||
1408 context->get(index)->IsTheHole()) {
1409 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 }
1411 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001412 // Slow case: The property is in the context extension object of a
1413 // function context or the global object of a global context.
1414 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001415 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001417 JSReceiver::SetProperty(object, name, initial_value, mode,
1418 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 }
1420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001423 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // "declared" in the function context's extension context or as a
1425 // property of the the global object.
1426 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001427 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001429 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001430 // Context extension objects are allocated lazily.
1431 ASSERT(context->IsFunctionContext());
1432 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001435 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 // Declare the property by setting it to the initial value if provided,
1439 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1440 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001441 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001442 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001443 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001444 // Declaring a const context slot is a conflicting declaration if
1445 // there is a callback with that name in a prototype. It is
1446 // allowed to introduce const variables in
1447 // JSContextExtensionObjects. They are treated specially in
1448 // SetProperty and no setters are invoked for those since they are
1449 // not real JSObjects.
1450 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001451 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001452 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001453 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001454 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001455 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001456 }
1457 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001458 if (object->IsJSGlobalObject()) {
1459 // Define own property on the global object.
1460 RETURN_IF_EMPTY_HANDLE(isolate,
1461 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
1462 } else {
1463 RETURN_IF_EMPTY_HANDLE(isolate,
1464 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
1465 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001466 }
1467
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001468 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469}
1470
1471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001472RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001474 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001475 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477
1478 // Determine if we need to assign to the variable if it already
1479 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001480 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1481 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001483 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001485 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001486 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1487 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1488 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
1490 // According to ECMA-262, section 12.2, page 62, the property must
1491 // not be deletable.
1492 PropertyAttributes attributes = DONT_DELETE;
1493
1494 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001495 // there, there is a property with this name in the prototype chain.
1496 // We follow Safari and Firefox behavior and only set the property
1497 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001498 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001499 // Note that objects can have hidden prototypes, so we need to traverse
1500 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001502 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001503 while (object->IsJSObject() &&
1504 JSObject::cast(object)->map()->is_hidden_prototype()) {
1505 JSObject* raw_holder = JSObject::cast(object);
1506 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001507 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 HandleScope handle_scope(isolate);
1509 Handle<JSObject> holder(raw_holder);
1510 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1511 // Update the raw pointer in case it's changed due to GC.
1512 raw_holder = *holder;
1513 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1514 // Found an interceptor that's not read only.
1515 if (assign) {
1516 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001517 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001518 } else {
1519 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001520 }
1521 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001522 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 }
1525
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001528 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001529 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001530 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001531 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532}
1533
1534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001535RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 // All constants are declared with an initial value. The name
1537 // of the constant is the first argument and the initial value
1538 // is the second.
1539 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001540 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541 Handle<Object> value = args.at<Object>(1);
1542
1543 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545
1546 // According to ECMA-262, section 12.2, page 62, the property must
1547 // not be deletable. Since it's a const, it must be READ_ONLY too.
1548 PropertyAttributes attributes =
1549 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1550
1551 // Lookup the property locally in the global object. If it isn't
1552 // there, we add the property and take special precautions to always
1553 // add it as a local property even in case of callbacks in the
1554 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001555 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001556 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001557 global->LocalLookup(*name, &lookup);
1558 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001559 return global->SetLocalPropertyIgnoreAttributes(*name,
1560 *value,
1561 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 }
1563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 HandleScope handle_scope(isolate);
1568 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001570 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 // property through an interceptor and only do it if it's
1572 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001573 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001574 RETURN_IF_EMPTY_HANDLE(
1575 isolate,
1576 JSReceiver::SetProperty(global, name, value, attributes,
1577 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 return *value;
1579 }
1580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582 // constant. For now, we determine this by checking if the
1583 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001584 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 PropertyType type = lookup.type();
1586 if (type == FIELD) {
1587 FixedArray* properties = global->properties();
1588 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001589 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 properties->set(index, *value);
1591 }
1592 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001593 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1594 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001595 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596 }
1597 } else {
1598 // Ignore re-initialization of constants that have already been
1599 // assigned a function value.
1600 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1601 }
1602
1603 // Use the set value as the result of the operation.
1604 return *value;
1605}
1606
1607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001608RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001609 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 ASSERT(args.length() == 3);
1611
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001612 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001615 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001616 RUNTIME_ASSERT(args[1]->IsContext());
1617 Handle<Context> context(Context::cast(args[1])->declaration_context());
1618
1619 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620
1621 int index;
1622 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001623 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001624 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001625 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001626 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 ASSERT(holder->IsContext());
1630 // Property was found in a context. Perform the assignment if we
1631 // found some non-constant or an uninitialized constant.
1632 Handle<Context> context = Handle<Context>::cast(holder);
1633 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1634 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 }
1636 return *value;
1637 }
1638
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001639 // The property could not be found, we introduce it as a property of the
1640 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001641 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001642 Handle<JSObject> global = Handle<JSObject>(
1643 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001644 // Strict mode not needed (const disallowed in strict mode).
1645 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001646 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001647 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648 return *value;
1649 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001650
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001651 // The property was present in some function's context extension object,
1652 // as a property on the subject of a with, or as a property of the global
1653 // object.
1654 //
1655 // In most situations, eval-introduced consts should still be present in
1656 // the context extension object. However, because declaration and
1657 // initialization are separate, the property might have been deleted
1658 // before we reach the initialization point.
1659 //
1660 // Example:
1661 //
1662 // function f() { eval("delete x; const x;"); }
1663 //
1664 // In that case, the initialization behaves like a normal assignment.
1665 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001667 if (*object == context->extension()) {
1668 // This is the property that was introduced by the const declaration.
1669 // Set it if it hasn't been set before. NOTE: We cannot use
1670 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001671 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001672 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001673 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001674 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1675
1676 PropertyType type = lookup.type();
1677 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001678 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001679 int index = lookup.GetFieldIndex();
1680 if (properties->get(index)->IsTheHole()) {
1681 properties->set(index, *value);
1682 }
1683 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1685 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001686 }
1687 } else {
1688 // We should not reach here. Any real, named property should be
1689 // either a field or a dictionary slot.
1690 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 }
1692 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001693 // The property was found on some other object. Set it if it is not a
1694 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001695 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001696 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001697 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001699 JSReceiver::SetProperty(object, name, value, attributes,
1700 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001704 return *value;
1705}
1706
1707
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001708RUNTIME_FUNCTION(MaybeObject*,
1709 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001711 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001712 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001713 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001714 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001715 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001716 }
1717 return *object;
1718}
1719
1720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001721RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001723 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001724 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1725 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001726 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001727 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001728 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001729 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001730 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001731 RUNTIME_ASSERT(index >= 0);
1732 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001733 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001734 Handle<Object> result = RegExpImpl::Exec(regexp,
1735 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001736 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001737 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001738 if (result.is_null()) return Failure::Exception();
1739 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740}
1741
1742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001743RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001745 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001746 if (elements_count < 0 ||
1747 elements_count > FixedArray::kMaxLength ||
1748 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001750 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751 Object* new_object;
1752 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001754 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1755 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001756 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1758 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001759 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1760 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001761 {
1762 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001766 }
1767 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001769 array->set_elements(elements);
1770 array->set_length(Smi::FromInt(elements_count));
1771 // Write in-object properties after the length of the array.
1772 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1773 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1774 return array;
1775}
1776
1777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001778RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001779 AssertNoAllocation no_alloc;
1780 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001781 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1782 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001783
1784 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786
1787 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001789
1790 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792
1793 Map* map = regexp->map();
1794 Object* constructor = map->constructor();
1795 if (constructor->IsJSFunction() &&
1796 JSFunction::cast(constructor)->initial_map() == map) {
1797 // If we still have the original map, set in-object properties directly.
1798 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001799 // Both true and false are immovable immortal objects so no need for write
1800 // barrier.
1801 regexp->InObjectPropertyAtPut(
1802 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1803 regexp->InObjectPropertyAtPut(
1804 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1805 regexp->InObjectPropertyAtPut(
1806 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001807 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1808 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001809 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001810 return regexp;
1811 }
1812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001814 PropertyAttributes final =
1815 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1816 PropertyAttributes writable =
1817 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001819 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001821 source,
1822 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001823 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001825 global,
1826 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001827 ASSERT(!result->IsFailure());
1828 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001830 ignoreCase,
1831 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001832 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001834 multiline,
1835 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001836 ASSERT(!result->IsFailure());
1837 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001839 Smi::FromInt(0),
1840 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001841 ASSERT(!result->IsFailure());
1842 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001843 return regexp;
1844}
1845
1846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001847RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001848 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001849 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001850 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001851 // This is necessary to enable fast checks for absence of elements
1852 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001854 return Smi::FromInt(0);
1855}
1856
1857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1859 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001860 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001861 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1863 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1864 Handle<JSFunction> optimized =
1865 isolate->factory()->NewFunction(key,
1866 JS_OBJECT_TYPE,
1867 JSObject::kHeaderSize,
1868 code,
1869 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001871 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001872 return optimized;
1873}
1874
1875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001876RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001879 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001880
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001881 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1882 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1883 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1884 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1885 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1886 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1887 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001888
1889 return *holder;
1890}
1891
1892
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001893RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001894 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001895 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001896
1897 if (!callable->IsJSFunction()) {
1898 HandleScope scope(isolate);
1899 bool threw = false;
1900 Handle<Object> delegate =
1901 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1902 if (threw) return Failure::Exception();
1903 callable = JSFunction::cast(*delegate);
1904 }
1905 JSFunction* function = JSFunction::cast(callable);
1906
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001907 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001908 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001909 return isolate->heap()->undefined_value();
1910 }
1911 // Returns undefined for strict or native functions, or
1912 // the associated global receiver for "normal" functions.
1913
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001914 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001915 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001916 return global_context->global()->global_receiver();
1917}
1918
1919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001920RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001922 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001923 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001924 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 Handle<String> pattern = args.at<String>(2);
1926 Handle<String> flags = args.at<String>(3);
1927
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001928 // Get the RegExp function from the context in the literals array.
1929 // This is the RegExp function from the context in which the
1930 // function was created. We do not use the RegExp function from the
1931 // current global context because this might be the RegExp function
1932 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001933 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001934 Handle<JSFunction>(
1935 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936 // Compute the regular expression literal.
1937 bool has_pending_exception;
1938 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001939 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1940 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943 return Failure::Exception();
1944 }
1945 literals->set(index, *regexp);
1946 return *regexp;
1947}
1948
1949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001950RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 NoHandleAllocation ha;
1952 ASSERT(args.length() == 1);
1953
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001954 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001955 return f->shared()->name();
1956}
1957
1958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001959RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001960 NoHandleAllocation ha;
1961 ASSERT(args.length() == 2);
1962
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001963 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1964 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001965 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001967}
1968
1969
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001970RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1971 NoHandleAllocation ha;
1972 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001973 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001974 return isolate->heap()->ToBoolean(
1975 f->shared()->name_should_print_as_anonymous());
1976}
1977
1978
1979RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1980 NoHandleAllocation ha;
1981 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001982 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001983 f->shared()->set_name_should_print_as_anonymous(true);
1984 return isolate->heap()->undefined_value();
1985}
1986
1987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001988RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001989 NoHandleAllocation ha;
1990 ASSERT(args.length() == 1);
1991
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001992 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001993 Object* obj = f->RemovePrototype();
1994 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001995
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001996 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001997}
1998
1999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002000RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002001 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 ASSERT(args.length() == 1);
2003
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002004 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002005 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2006 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002007
2008 return *GetScriptWrapper(Handle<Script>::cast(script));
2009}
2010
2011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002012RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002013 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 ASSERT(args.length() == 1);
2015
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002016 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002017 Handle<SharedFunctionInfo> shared(f->shared());
2018 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019}
2020
2021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002022RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023 NoHandleAllocation ha;
2024 ASSERT(args.length() == 1);
2025
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002026 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002027 int pos = fun->shared()->start_position();
2028 return Smi::FromInt(pos);
2029}
2030
2031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002032RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002033 ASSERT(args.length() == 2);
2034
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002035 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002036 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2037
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002038 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2039
2040 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002041 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002042}
2043
2044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002045RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002046 NoHandleAllocation ha;
2047 ASSERT(args.length() == 2);
2048
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002049 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2050 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002052 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053}
2054
2055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002056RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002057 NoHandleAllocation ha;
2058 ASSERT(args.length() == 2);
2059
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002060 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2061 CONVERT_SMI_ARG_CHECKED(length, 1);
2062 fun->shared()->set_length(length);
2063 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064}
2065
2066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002067RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002068 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002069 ASSERT(args.length() == 2);
2070
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002071 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002072 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002073 Object* obj;
2074 { MaybeObject* maybe_obj =
2075 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2076 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2077 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 return args[0]; // return TOS
2079}
2080
2081
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002082RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2083 NoHandleAllocation ha;
2084 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002085 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002086
2087 MaybeObject* maybe_name =
2088 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2089 String* name;
2090 if (!maybe_name->To(&name)) return maybe_name;
2091
2092 if (function->HasFastProperties()) {
2093 // Construct a new field descriptor with updated attributes.
2094 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2095 int index = instance_desc->Search(name);
2096 ASSERT(index != DescriptorArray::kNotFound);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002097 PropertyDetails details = instance_desc->GetDetails(index);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002098 CallbacksDescriptor new_desc(name,
2099 instance_desc->GetValue(index),
2100 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2101 details.index());
2102 // Construct a new field descriptors array containing the new descriptor.
2103 Object* descriptors_unchecked;
2104 { MaybeObject* maybe_descriptors_unchecked =
2105 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2106 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2107 return maybe_descriptors_unchecked;
2108 }
2109 }
2110 DescriptorArray* new_descriptors =
2111 DescriptorArray::cast(descriptors_unchecked);
2112 // Create a new map featuring the new field descriptors array.
2113 Object* map_unchecked;
2114 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2115 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2116 return maybe_map_unchecked;
2117 }
2118 }
2119 Map* new_map = Map::cast(map_unchecked);
2120 new_map->set_instance_descriptors(new_descriptors);
2121 function->set_map(new_map);
2122 } else { // Dictionary properties.
2123 // Directly manipulate the property details.
2124 int entry = function->property_dictionary()->FindEntry(name);
2125 ASSERT(entry != StringDictionary::kNotFound);
2126 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2127 PropertyDetails new_details(
2128 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2129 details.type(),
2130 details.index());
2131 function->property_dictionary()->DetailsAtPut(entry, new_details);
2132 }
2133 return function;
2134}
2135
2136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002137RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002138 NoHandleAllocation ha;
2139 ASSERT(args.length() == 1);
2140
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002141 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002142 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002143}
2144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002146RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002147 NoHandleAllocation ha;
2148 ASSERT(args.length() == 1);
2149
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002150 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002151 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002152}
2153
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002155RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002157 ASSERT(args.length() == 2);
2158
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002159 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002160 Handle<Object> code = args.at<Object>(1);
2161
2162 Handle<Context> context(target->context());
2163
2164 if (!code->IsNull()) {
2165 RUNTIME_ASSERT(code->IsJSFunction());
2166 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002167 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002168
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002169 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002170 return Failure::Exception();
2171 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002172 // Since we don't store the source for this we should never
2173 // optimize this.
2174 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002175 // Set the code, scope info, formal parameter count,
2176 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002177 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002178 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002179 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002182 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002183 // Set the source code of the target function to undefined.
2184 // SetCode is only used for built-in constructors like String,
2185 // Array, and Object, and some web code
2186 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002188 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002189 // Clear the optimization hints related to the compiled code as these are no
2190 // longer valid when the code is overwritten.
2191 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002192 context = Handle<Context>(fun->context());
2193
2194 // Make sure we get a fresh copy of the literal vector to avoid
2195 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002196 int number_of_literals = fun->NumberOfLiterals();
2197 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002200 // Insert the object, regexp and array functions in the literals
2201 // array prefix. These are the functions that will be used when
2202 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002203 literals->set(JSFunction::kLiteralGlobalContextIndex,
2204 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002205 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002206 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002207 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002208
2209 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2210 isolate->logger()->LogExistingFunction(
2211 shared, Handle<Code>(shared->code()));
2212 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213 }
2214
2215 target->set_context(*context);
2216 return *target;
2217}
2218
2219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002222 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002223 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002224 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002225 RUNTIME_ASSERT(num >= 0);
2226 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002228}
2229
2230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2232 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002234 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002236 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002237 }
2238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240}
2241
2242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002243RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002244 NoHandleAllocation ha;
2245 ASSERT(args.length() == 2);
2246
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002247 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002248 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251 uint32_t i = 0;
2252 if (index->IsSmi()) {
2253 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002255 i = value;
2256 } else {
2257 ASSERT(index->IsHeapNumber());
2258 double value = HeapNumber::cast(index)->value();
2259 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002260 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002261
2262 // Flatten the string. If someone wants to get a char at an index
2263 // in a cons string, it is likely that more indices will be
2264 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002265 Object* flat;
2266 { MaybeObject* maybe_flat = subject->TryFlatten();
2267 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2268 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002269 subject = String::cast(flat);
2270
2271 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002273 }
2274
2275 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002276}
2277
2278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002279RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280 NoHandleAllocation ha;
2281 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283}
2284
lrn@chromium.org25156de2010-04-06 13:10:27 +00002285
2286class FixedArrayBuilder {
2287 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2289 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002290 length_(0),
2291 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292 // Require a non-zero initial size. Ensures that doubling the size to
2293 // extend the array will work.
2294 ASSERT(initial_capacity > 0);
2295 }
2296
2297 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2298 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002299 length_(0),
2300 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002301 // Require a non-zero initial size. Ensures that doubling the size to
2302 // extend the array will work.
2303 ASSERT(backing_store->length() > 0);
2304 }
2305
2306 bool HasCapacity(int elements) {
2307 int length = array_->length();
2308 int required_length = length_ + elements;
2309 return (length >= required_length);
2310 }
2311
2312 void EnsureCapacity(int elements) {
2313 int length = array_->length();
2314 int required_length = length_ + elements;
2315 if (length < required_length) {
2316 int new_length = length;
2317 do {
2318 new_length *= 2;
2319 } while (new_length < required_length);
2320 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002321 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002322 array_->CopyTo(0, *extended_array, 0, length_);
2323 array_ = extended_array;
2324 }
2325 }
2326
2327 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002328 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 ASSERT(length_ < capacity());
2330 array_->set(length_, value);
2331 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002332 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002333 }
2334
2335 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002336 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002337 ASSERT(length_ < capacity());
2338 array_->set(length_, value);
2339 length_++;
2340 }
2341
2342 Handle<FixedArray> array() {
2343 return array_;
2344 }
2345
2346 int length() {
2347 return length_;
2348 }
2349
2350 int capacity() {
2351 return array_->length();
2352 }
2353
2354 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002355 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356 result_array->set_length(Smi::FromInt(length_));
2357 return result_array;
2358 }
2359
2360 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002361 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002362 target_array->set_length(Smi::FromInt(length_));
2363 return target_array;
2364 }
2365
2366 private:
2367 Handle<FixedArray> array_;
2368 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002369 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002370};
2371
2372
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002373// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002374const int kStringBuilderConcatHelperLengthBits = 11;
2375const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376
2377template <typename schar>
2378static inline void StringBuilderConcatHelper(String*,
2379 schar*,
2380 FixedArray*,
2381 int);
2382
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2384 StringBuilderSubstringLength;
2385typedef BitField<int,
2386 kStringBuilderConcatHelperLengthBits,
2387 kStringBuilderConcatHelperPositionBits>
2388 StringBuilderSubstringPosition;
2389
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002390
2391class ReplacementStringBuilder {
2392 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002393 ReplacementStringBuilder(Heap* heap,
2394 Handle<String> subject,
2395 int estimated_part_count)
2396 : heap_(heap),
2397 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002398 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002400 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002401 // Require a non-zero initial size. Ensures that doubling the size to
2402 // extend the array will work.
2403 ASSERT(estimated_part_count > 0);
2404 }
2405
lrn@chromium.org25156de2010-04-06 13:10:27 +00002406 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2407 int from,
2408 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002409 ASSERT(from >= 0);
2410 int length = to - from;
2411 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002412 if (StringBuilderSubstringLength::is_valid(length) &&
2413 StringBuilderSubstringPosition::is_valid(from)) {
2414 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2415 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002418 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002419 builder->Add(Smi::FromInt(-length));
2420 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002421 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002422 }
2423
2424
2425 void EnsureCapacity(int elements) {
2426 array_builder_.EnsureCapacity(elements);
2427 }
2428
2429
2430 void AddSubjectSlice(int from, int to) {
2431 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002432 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 }
2434
2435
2436 void AddString(Handle<String> string) {
2437 int length = string->length();
2438 ASSERT(length > 0);
2439 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002440 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002441 is_ascii_ = false;
2442 }
2443 IncrementCharacterCount(length);
2444 }
2445
2446
2447 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002448 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002449 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 }
2451
2452 Handle<String> joined_string;
2453 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002454 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002455 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 char* char_buffer = seq->GetChars();
2457 StringBuilderConcatHelper(*subject_,
2458 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 *array_builder_.array(),
2460 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 } else {
2463 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002464 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002465 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002466 uc16* char_buffer = seq->GetChars();
2467 StringBuilderConcatHelper(*subject_,
2468 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002469 *array_builder_.array(),
2470 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002471 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 }
2473 return joined_string;
2474 }
2475
2476
2477 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002478 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 V8::FatalProcessOutOfMemory("String.replace result too large.");
2480 }
2481 character_count_ += by;
2482 }
2483
lrn@chromium.org25156de2010-04-06 13:10:27 +00002484 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002485 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002487
lrn@chromium.org25156de2010-04-06 13:10:27 +00002488 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002489 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2490 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002491 }
2492
2493
ager@chromium.org04921a82011-06-27 13:21:41 +00002494 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2495 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002496 }
2497
2498
2499 void AddElement(Object* element) {
2500 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002501 ASSERT(array_builder_.capacity() > array_builder_.length());
2502 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 }
2504
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002505 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002506 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002507 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002508 int character_count_;
2509 bool is_ascii_;
2510};
2511
2512
2513class CompiledReplacement {
2514 public:
2515 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002516 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002517
2518 void Compile(Handle<String> replacement,
2519 int capture_count,
2520 int subject_length);
2521
2522 void Apply(ReplacementStringBuilder* builder,
2523 int match_from,
2524 int match_to,
2525 Handle<JSArray> last_match_info);
2526
2527 // Number of distinct parts of the replacement pattern.
2528 int parts() {
2529 return parts_.length();
2530 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002531
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002532 bool simple_hint() {
2533 return simple_hint_;
2534 }
2535
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002536 private:
2537 enum PartType {
2538 SUBJECT_PREFIX = 1,
2539 SUBJECT_SUFFIX,
2540 SUBJECT_CAPTURE,
2541 REPLACEMENT_SUBSTRING,
2542 REPLACEMENT_STRING,
2543
2544 NUMBER_OF_PART_TYPES
2545 };
2546
2547 struct ReplacementPart {
2548 static inline ReplacementPart SubjectMatch() {
2549 return ReplacementPart(SUBJECT_CAPTURE, 0);
2550 }
2551 static inline ReplacementPart SubjectCapture(int capture_index) {
2552 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2553 }
2554 static inline ReplacementPart SubjectPrefix() {
2555 return ReplacementPart(SUBJECT_PREFIX, 0);
2556 }
2557 static inline ReplacementPart SubjectSuffix(int subject_length) {
2558 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2559 }
2560 static inline ReplacementPart ReplacementString() {
2561 return ReplacementPart(REPLACEMENT_STRING, 0);
2562 }
2563 static inline ReplacementPart ReplacementSubString(int from, int to) {
2564 ASSERT(from >= 0);
2565 ASSERT(to > from);
2566 return ReplacementPart(-from, to);
2567 }
2568
2569 // If tag <= 0 then it is the negation of a start index of a substring of
2570 // the replacement pattern, otherwise it's a value from PartType.
2571 ReplacementPart(int tag, int data)
2572 : tag(tag), data(data) {
2573 // Must be non-positive or a PartType value.
2574 ASSERT(tag < NUMBER_OF_PART_TYPES);
2575 }
2576 // Either a value of PartType or a non-positive number that is
2577 // the negation of an index into the replacement string.
2578 int tag;
2579 // The data value's interpretation depends on the value of tag:
2580 // tag == SUBJECT_PREFIX ||
2581 // tag == SUBJECT_SUFFIX: data is unused.
2582 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2583 // tag == REPLACEMENT_SUBSTRING ||
2584 // tag == REPLACEMENT_STRING: data is index into array of substrings
2585 // of the replacement string.
2586 // tag <= 0: Temporary representation of the substring of the replacement
2587 // string ranging over -tag .. data.
2588 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2589 // substring objects.
2590 int data;
2591 };
2592
2593 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002594 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002595 Vector<Char> characters,
2596 int capture_count,
2597 int subject_length) {
2598 int length = characters.length();
2599 int last = 0;
2600 for (int i = 0; i < length; i++) {
2601 Char c = characters[i];
2602 if (c == '$') {
2603 int next_index = i + 1;
2604 if (next_index == length) { // No next character!
2605 break;
2606 }
2607 Char c2 = characters[next_index];
2608 switch (c2) {
2609 case '$':
2610 if (i > last) {
2611 // There is a substring before. Include the first "$".
2612 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2613 last = next_index + 1; // Continue after the second "$".
2614 } else {
2615 // Let the next substring start with the second "$".
2616 last = next_index;
2617 }
2618 i = next_index;
2619 break;
2620 case '`':
2621 if (i > last) {
2622 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2623 }
2624 parts->Add(ReplacementPart::SubjectPrefix());
2625 i = next_index;
2626 last = i + 1;
2627 break;
2628 case '\'':
2629 if (i > last) {
2630 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2631 }
2632 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2633 i = next_index;
2634 last = i + 1;
2635 break;
2636 case '&':
2637 if (i > last) {
2638 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2639 }
2640 parts->Add(ReplacementPart::SubjectMatch());
2641 i = next_index;
2642 last = i + 1;
2643 break;
2644 case '0':
2645 case '1':
2646 case '2':
2647 case '3':
2648 case '4':
2649 case '5':
2650 case '6':
2651 case '7':
2652 case '8':
2653 case '9': {
2654 int capture_ref = c2 - '0';
2655 if (capture_ref > capture_count) {
2656 i = next_index;
2657 continue;
2658 }
2659 int second_digit_index = next_index + 1;
2660 if (second_digit_index < length) {
2661 // Peek ahead to see if we have two digits.
2662 Char c3 = characters[second_digit_index];
2663 if ('0' <= c3 && c3 <= '9') { // Double digits.
2664 int double_digit_ref = capture_ref * 10 + c3 - '0';
2665 if (double_digit_ref <= capture_count) {
2666 next_index = second_digit_index;
2667 capture_ref = double_digit_ref;
2668 }
2669 }
2670 }
2671 if (capture_ref > 0) {
2672 if (i > last) {
2673 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2674 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002675 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2677 last = next_index + 1;
2678 }
2679 i = next_index;
2680 break;
2681 }
2682 default:
2683 i = next_index;
2684 break;
2685 }
2686 }
2687 }
2688 if (length > last) {
2689 if (last == 0) {
2690 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002691 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002692 } else {
2693 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2694 }
2695 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002696 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002697 }
2698
2699 ZoneList<ReplacementPart> parts_;
2700 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002701 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702};
2703
2704
2705void CompiledReplacement::Compile(Handle<String> replacement,
2706 int capture_count,
2707 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002708 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002709 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002710 String::FlatContent content = replacement->GetFlatContent();
2711 ASSERT(content.IsFlat());
2712 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002713 simple_hint_ = ParseReplacementPattern(&parts_,
2714 content.ToAsciiVector(),
2715 capture_count,
2716 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002717 } else {
2718 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002719 simple_hint_ = ParseReplacementPattern(&parts_,
2720 content.ToUC16Vector(),
2721 capture_count,
2722 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002723 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002725 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002726 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002727 int substring_index = 0;
2728 for (int i = 0, n = parts_.length(); i < n; i++) {
2729 int tag = parts_[i].tag;
2730 if (tag <= 0) { // A replacement string slice.
2731 int from = -tag;
2732 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002733 replacement_substrings_.Add(
2734 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002735 parts_[i].tag = REPLACEMENT_SUBSTRING;
2736 parts_[i].data = substring_index;
2737 substring_index++;
2738 } else if (tag == REPLACEMENT_STRING) {
2739 replacement_substrings_.Add(replacement);
2740 parts_[i].data = substring_index;
2741 substring_index++;
2742 }
2743 }
2744}
2745
2746
2747void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2748 int match_from,
2749 int match_to,
2750 Handle<JSArray> last_match_info) {
2751 for (int i = 0, n = parts_.length(); i < n; i++) {
2752 ReplacementPart part = parts_[i];
2753 switch (part.tag) {
2754 case SUBJECT_PREFIX:
2755 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2756 break;
2757 case SUBJECT_SUFFIX: {
2758 int subject_length = part.data;
2759 if (match_to < subject_length) {
2760 builder->AddSubjectSlice(match_to, subject_length);
2761 }
2762 break;
2763 }
2764 case SUBJECT_CAPTURE: {
2765 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002766 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002767 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2768 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2769 if (from >= 0 && to > from) {
2770 builder->AddSubjectSlice(from, to);
2771 }
2772 break;
2773 }
2774 case REPLACEMENT_SUBSTRING:
2775 case REPLACEMENT_STRING:
2776 builder->AddString(replacement_substrings_[part.data]);
2777 break;
2778 default:
2779 UNREACHABLE();
2780 }
2781 }
2782}
2783
2784
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002785void FindAsciiStringIndices(Vector<const char> subject,
2786 char pattern,
2787 ZoneList<int>* indices,
2788 unsigned int limit) {
2789 ASSERT(limit > 0);
2790 // Collect indices of pattern in subject using memchr.
2791 // Stop after finding at most limit values.
2792 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2793 const char* subject_end = subject_start + subject.length();
2794 const char* pos = subject_start;
2795 while (limit > 0) {
2796 pos = reinterpret_cast<const char*>(
2797 memchr(pos, pattern, subject_end - pos));
2798 if (pos == NULL) return;
2799 indices->Add(static_cast<int>(pos - subject_start));
2800 pos++;
2801 limit--;
2802 }
2803}
2804
2805
2806template <typename SubjectChar, typename PatternChar>
2807void FindStringIndices(Isolate* isolate,
2808 Vector<const SubjectChar> subject,
2809 Vector<const PatternChar> pattern,
2810 ZoneList<int>* indices,
2811 unsigned int limit) {
2812 ASSERT(limit > 0);
2813 // Collect indices of pattern in subject.
2814 // Stop after finding at most limit values.
2815 int pattern_length = pattern.length();
2816 int index = 0;
2817 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2818 while (limit > 0) {
2819 index = search.Search(subject, index);
2820 if (index < 0) return;
2821 indices->Add(index);
2822 index += pattern_length;
2823 limit--;
2824 }
2825}
2826
2827
2828void FindStringIndicesDispatch(Isolate* isolate,
2829 String* subject,
2830 String* pattern,
2831 ZoneList<int>* indices,
2832 unsigned int limit) {
2833 {
2834 AssertNoAllocation no_gc;
2835 String::FlatContent subject_content = subject->GetFlatContent();
2836 String::FlatContent pattern_content = pattern->GetFlatContent();
2837 ASSERT(subject_content.IsFlat());
2838 ASSERT(pattern_content.IsFlat());
2839 if (subject_content.IsAscii()) {
2840 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2841 if (pattern_content.IsAscii()) {
2842 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2843 if (pattern_vector.length() == 1) {
2844 FindAsciiStringIndices(subject_vector,
2845 pattern_vector[0],
2846 indices,
2847 limit);
2848 } else {
2849 FindStringIndices(isolate,
2850 subject_vector,
2851 pattern_vector,
2852 indices,
2853 limit);
2854 }
2855 } else {
2856 FindStringIndices(isolate,
2857 subject_vector,
2858 pattern_content.ToUC16Vector(),
2859 indices,
2860 limit);
2861 }
2862 } else {
2863 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002864 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002865 FindStringIndices(isolate,
2866 subject_vector,
2867 pattern_content.ToAsciiVector(),
2868 indices,
2869 limit);
2870 } else {
2871 FindStringIndices(isolate,
2872 subject_vector,
2873 pattern_content.ToUC16Vector(),
2874 indices,
2875 limit);
2876 }
2877 }
2878 }
2879}
2880
2881
2882template<typename ResultSeqString>
2883MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2884 Isolate* isolate,
2885 Handle<String> subject,
2886 Handle<JSRegExp> pattern_regexp,
2887 Handle<String> replacement) {
2888 ASSERT(subject->IsFlat());
2889 ASSERT(replacement->IsFlat());
2890
2891 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2892 ZoneList<int> indices(8);
2893 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2894 String* pattern =
2895 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2896 int subject_len = subject->length();
2897 int pattern_len = pattern->length();
2898 int replacement_len = replacement->length();
2899
2900 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2901
2902 int matches = indices.length();
2903 if (matches == 0) return *subject;
2904
2905 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2906 int subject_pos = 0;
2907 int result_pos = 0;
2908
2909 Handle<ResultSeqString> result;
2910 if (ResultSeqString::kHasAsciiEncoding) {
2911 result = Handle<ResultSeqString>::cast(
2912 isolate->factory()->NewRawAsciiString(result_len));
2913 } else {
2914 result = Handle<ResultSeqString>::cast(
2915 isolate->factory()->NewRawTwoByteString(result_len));
2916 }
2917
2918 for (int i = 0; i < matches; i++) {
2919 // Copy non-matched subject content.
2920 if (subject_pos < indices.at(i)) {
2921 String::WriteToFlat(*subject,
2922 result->GetChars() + result_pos,
2923 subject_pos,
2924 indices.at(i));
2925 result_pos += indices.at(i) - subject_pos;
2926 }
2927
2928 // Replace match.
2929 if (replacement_len > 0) {
2930 String::WriteToFlat(*replacement,
2931 result->GetChars() + result_pos,
2932 0,
2933 replacement_len);
2934 result_pos += replacement_len;
2935 }
2936
2937 subject_pos = indices.at(i) + pattern_len;
2938 }
2939 // Add remaining subject content at the end.
2940 if (subject_pos < subject_len) {
2941 String::WriteToFlat(*subject,
2942 result->GetChars() + result_pos,
2943 subject_pos,
2944 subject_len);
2945 }
2946 return *result;
2947}
2948
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002949
lrn@chromium.org303ada72010-10-27 09:33:13 +00002950MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002951 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002952 String* subject,
2953 JSRegExp* regexp,
2954 String* replacement,
2955 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002956 ASSERT(subject->IsFlat());
2957 ASSERT(replacement->IsFlat());
2958
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002959 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002960
2961 int length = subject->length();
2962 Handle<String> subject_handle(subject);
2963 Handle<JSRegExp> regexp_handle(regexp);
2964 Handle<String> replacement_handle(replacement);
2965 Handle<JSArray> last_match_info_handle(last_match_info);
2966 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2967 subject_handle,
2968 0,
2969 last_match_info_handle);
2970 if (match.is_null()) {
2971 return Failure::Exception();
2972 }
2973 if (match->IsNull()) {
2974 return *subject_handle;
2975 }
2976
2977 int capture_count = regexp_handle->CaptureCount();
2978
2979 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002980 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002981 CompiledReplacement compiled_replacement;
2982 compiled_replacement.Compile(replacement_handle,
2983 capture_count,
2984 length);
2985
2986 bool is_global = regexp_handle->GetFlags().is_global();
2987
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002988 // Shortcut for simple non-regexp global replacements
2989 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002990 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002991 compiled_replacement.simple_hint()) {
2992 if (subject_handle->HasOnlyAsciiChars() &&
2993 replacement_handle->HasOnlyAsciiChars()) {
2994 return StringReplaceStringWithString<SeqAsciiString>(
2995 isolate, subject_handle, regexp_handle, replacement_handle);
2996 } else {
2997 return StringReplaceStringWithString<SeqTwoByteString>(
2998 isolate, subject_handle, regexp_handle, replacement_handle);
2999 }
3000 }
3001
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003002 // Guessing the number of parts that the final result string is built
3003 // from. Global regexps can match any number of times, so we guess
3004 // conservatively.
3005 int expected_parts =
3006 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003007 ReplacementStringBuilder builder(isolate->heap(),
3008 subject_handle,
3009 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003010
3011 // Index of end of last match.
3012 int prev = 0;
3013
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003014 // Number of parts added by compiled replacement plus preceeding
3015 // string and possibly suffix after last match. It is possible for
3016 // all components to use two elements when encoded as two smis.
3017 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003018 bool matched = true;
3019 do {
3020 ASSERT(last_match_info_handle->HasFastElements());
3021 // Increase the capacity of the builder before entering local handle-scope,
3022 // so its internal buffer can safely allocate a new handle if it grows.
3023 builder.EnsureCapacity(parts_added_per_loop);
3024
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003025 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003026 int start, end;
3027 {
3028 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003029 FixedArray* match_info_array =
3030 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003031
3032 ASSERT_EQ(capture_count * 2 + 2,
3033 RegExpImpl::GetLastCaptureCount(match_info_array));
3034 start = RegExpImpl::GetCapture(match_info_array, 0);
3035 end = RegExpImpl::GetCapture(match_info_array, 1);
3036 }
3037
3038 if (prev < start) {
3039 builder.AddSubjectSlice(prev, start);
3040 }
3041 compiled_replacement.Apply(&builder,
3042 start,
3043 end,
3044 last_match_info_handle);
3045 prev = end;
3046
3047 // Only continue checking for global regexps.
3048 if (!is_global) break;
3049
3050 // Continue from where the match ended, unless it was an empty match.
3051 int next = end;
3052 if (start == end) {
3053 next = end + 1;
3054 if (next > length) break;
3055 }
3056
3057 match = RegExpImpl::Exec(regexp_handle,
3058 subject_handle,
3059 next,
3060 last_match_info_handle);
3061 if (match.is_null()) {
3062 return Failure::Exception();
3063 }
3064 matched = !match->IsNull();
3065 } while (matched);
3066
3067 if (prev < length) {
3068 builder.AddSubjectSlice(prev, length);
3069 }
3070
3071 return *(builder.ToString());
3072}
3073
3074
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003075template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003076MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003077 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003078 String* subject,
3079 JSRegExp* regexp,
3080 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003081 ASSERT(subject->IsFlat());
3082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003083 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003084
3085 Handle<String> subject_handle(subject);
3086 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003087
3088 // Shortcut for simple non-regexp global replacements
3089 if (regexp_handle->GetFlags().is_global() &&
3090 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3091 Handle<String> empty_string_handle(HEAP->empty_string());
3092 if (subject_handle->HasOnlyAsciiChars()) {
3093 return StringReplaceStringWithString<SeqAsciiString>(
3094 isolate, subject_handle, regexp_handle, empty_string_handle);
3095 } else {
3096 return StringReplaceStringWithString<SeqTwoByteString>(
3097 isolate, subject_handle, regexp_handle, empty_string_handle);
3098 }
3099 }
3100
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003101 Handle<JSArray> last_match_info_handle(last_match_info);
3102 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3103 subject_handle,
3104 0,
3105 last_match_info_handle);
3106 if (match.is_null()) return Failure::Exception();
3107 if (match->IsNull()) return *subject_handle;
3108
3109 ASSERT(last_match_info_handle->HasFastElements());
3110
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003111 int start, end;
3112 {
3113 AssertNoAllocation match_info_array_is_not_in_a_handle;
3114 FixedArray* match_info_array =
3115 FixedArray::cast(last_match_info_handle->elements());
3116
3117 start = RegExpImpl::GetCapture(match_info_array, 0);
3118 end = RegExpImpl::GetCapture(match_info_array, 1);
3119 }
3120
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003121 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003122 int new_length = length - (end - start);
3123 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003124 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003125 }
3126 Handle<ResultSeqString> answer;
3127 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003128 answer = Handle<ResultSeqString>::cast(
3129 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003130 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 answer = Handle<ResultSeqString>::cast(
3132 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003133 }
3134
3135 // If the regexp isn't global, only match once.
3136 if (!regexp_handle->GetFlags().is_global()) {
3137 if (start > 0) {
3138 String::WriteToFlat(*subject_handle,
3139 answer->GetChars(),
3140 0,
3141 start);
3142 }
3143 if (end < length) {
3144 String::WriteToFlat(*subject_handle,
3145 answer->GetChars() + start,
3146 end,
3147 length);
3148 }
3149 return *answer;
3150 }
3151
3152 int prev = 0; // Index of end of last match.
3153 int next = 0; // Start of next search (prev unless last match was empty).
3154 int position = 0;
3155
3156 do {
3157 if (prev < start) {
3158 // Add substring subject[prev;start] to answer string.
3159 String::WriteToFlat(*subject_handle,
3160 answer->GetChars() + position,
3161 prev,
3162 start);
3163 position += start - prev;
3164 }
3165 prev = end;
3166 next = end;
3167 // Continue from where the match ended, unless it was an empty match.
3168 if (start == end) {
3169 next++;
3170 if (next > length) break;
3171 }
3172 match = RegExpImpl::Exec(regexp_handle,
3173 subject_handle,
3174 next,
3175 last_match_info_handle);
3176 if (match.is_null()) return Failure::Exception();
3177 if (match->IsNull()) break;
3178
3179 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003180 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003181 {
3182 AssertNoAllocation match_info_array_is_not_in_a_handle;
3183 FixedArray* match_info_array =
3184 FixedArray::cast(last_match_info_handle->elements());
3185 start = RegExpImpl::GetCapture(match_info_array, 0);
3186 end = RegExpImpl::GetCapture(match_info_array, 1);
3187 }
3188 } while (true);
3189
3190 if (prev < length) {
3191 // Add substring subject[prev;length] to answer string.
3192 String::WriteToFlat(*subject_handle,
3193 answer->GetChars() + position,
3194 prev,
3195 length);
3196 position += length - prev;
3197 }
3198
3199 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003200 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003201 }
3202
3203 // Shorten string and fill
3204 int string_size = ResultSeqString::SizeFor(position);
3205 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3206 int delta = allocated_string_size - string_size;
3207
3208 answer->set_length(position);
3209 if (delta == 0) return *answer;
3210
3211 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003212 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003213 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003214 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003215 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003216
3217 return *answer;
3218}
3219
3220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003221RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003222 ASSERT(args.length() == 4);
3223
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003224 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003225 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003226 Object* flat_subject;
3227 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3228 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3229 return maybe_flat_subject;
3230 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003231 }
3232 subject = String::cast(flat_subject);
3233 }
3234
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003235 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003236 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003237 Object* flat_replacement;
3238 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3239 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3240 return maybe_flat_replacement;
3241 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003242 }
3243 replacement = String::cast(flat_replacement);
3244 }
3245
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003246 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3247 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003248
3249 ASSERT(last_match_info->HasFastElements());
3250
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003251 if (replacement->length() == 0) {
3252 if (subject->HasOnlyAsciiChars()) {
3253 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003254 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003255 } else {
3256 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003257 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003258 }
3259 }
3260
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 return StringReplaceRegExpWithString(isolate,
3262 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003263 regexp,
3264 replacement,
3265 last_match_info);
3266}
3267
3268
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003269Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3270 Handle<String> subject,
3271 Handle<String> search,
3272 Handle<String> replace,
3273 bool* found,
3274 int recursion_limit) {
3275 if (recursion_limit == 0) return Handle<String>::null();
3276 if (subject->IsConsString()) {
3277 ConsString* cons = ConsString::cast(*subject);
3278 Handle<String> first = Handle<String>(cons->first());
3279 Handle<String> second = Handle<String>(cons->second());
3280 Handle<String> new_first =
3281 StringReplaceOneCharWithString(isolate,
3282 first,
3283 search,
3284 replace,
3285 found,
3286 recursion_limit - 1);
3287 if (*found) return isolate->factory()->NewConsString(new_first, second);
3288 if (new_first.is_null()) return new_first;
3289
3290 Handle<String> new_second =
3291 StringReplaceOneCharWithString(isolate,
3292 second,
3293 search,
3294 replace,
3295 found,
3296 recursion_limit - 1);
3297 if (*found) return isolate->factory()->NewConsString(first, new_second);
3298 if (new_second.is_null()) return new_second;
3299
3300 return subject;
3301 } else {
3302 int index = StringMatch(isolate, subject, search, 0);
3303 if (index == -1) return subject;
3304 *found = true;
3305 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3306 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3307 Handle<String> second =
3308 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3309 return isolate->factory()->NewConsString(cons1, second);
3310 }
3311}
3312
3313
3314RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3315 ASSERT(args.length() == 3);
3316 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003317 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3318 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3319 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003320
3321 // If the cons string tree is too deep, we simply abort the recursion and
3322 // retry with a flattened subject string.
3323 const int kRecursionLimit = 0x1000;
3324 bool found = false;
3325 Handle<String> result =
3326 Runtime::StringReplaceOneCharWithString(isolate,
3327 subject,
3328 search,
3329 replace,
3330 &found,
3331 kRecursionLimit);
3332 if (!result.is_null()) return *result;
3333 return *Runtime::StringReplaceOneCharWithString(isolate,
3334 FlattenGetString(subject),
3335 search,
3336 replace,
3337 &found,
3338 kRecursionLimit);
3339}
3340
3341
ager@chromium.org7c537e22008-10-16 08:43:32 +00003342// Perform string match of pattern on subject, starting at start index.
3343// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003344// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345int Runtime::StringMatch(Isolate* isolate,
3346 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003347 Handle<String> pat,
3348 int start_index) {
3349 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003350 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003351
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003352 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003353 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003355 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003356 if (start_index + pattern_length > subject_length) return -1;
3357
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003358 if (!sub->IsFlat()) FlattenString(sub);
3359 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003360
ager@chromium.org7c537e22008-10-16 08:43:32 +00003361 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003362 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003363 String::FlatContent seq_sub = sub->GetFlatContent();
3364 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003365
ager@chromium.org7c537e22008-10-16 08:43:32 +00003366 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003367 if (seq_pat.IsAscii()) {
3368 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3369 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003370 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003371 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003372 pat_vector,
3373 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003374 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003376 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 pat_vector,
3378 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003379 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003380 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3381 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 pat_vector,
3385 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003388 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 pat_vector,
3390 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003391}
3392
3393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003394RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003395 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003396 ASSERT(args.length() == 3);
3397
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003398 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3399 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003400
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003401 Object* index = args[2];
3402 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003403 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003404
ager@chromium.org870a0b62008-11-04 11:43:05 +00003405 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003406 int position =
3407 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003408 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409}
3410
3411
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003412template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003413static int StringMatchBackwards(Vector<const schar> subject,
3414 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003415 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003416 int pattern_length = pattern.length();
3417 ASSERT(pattern_length >= 1);
3418 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003419
3420 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003421 for (int i = 0; i < pattern_length; i++) {
3422 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003423 if (c > String::kMaxAsciiCharCode) {
3424 return -1;
3425 }
3426 }
3427 }
3428
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003429 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003431 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003432 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003433 while (j < pattern_length) {
3434 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003435 break;
3436 }
3437 j++;
3438 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003439 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003440 return i;
3441 }
3442 }
3443 return -1;
3444}
3445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003446RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003447 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 ASSERT(args.length() == 3);
3449
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003450 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3451 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003455 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003457 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003458 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003459
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003460 if (start_index + pat_length > sub_length) {
3461 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003462 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003464 if (pat_length == 0) {
3465 return Smi::FromInt(start_index);
3466 }
3467
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003468 if (!sub->IsFlat()) FlattenString(sub);
3469 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003470
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003471 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003472 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3473
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003474 String::FlatContent sub_content = sub->GetFlatContent();
3475 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003476
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003477 if (pat_content.IsAscii()) {
3478 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3479 if (sub_content.IsAscii()) {
3480 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003481 pat_vector,
3482 start_index);
3483 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003484 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003485 pat_vector,
3486 start_index);
3487 }
3488 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003489 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3490 if (sub_content.IsAscii()) {
3491 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003492 pat_vector,
3493 start_index);
3494 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003495 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003496 pat_vector,
3497 start_index);
3498 }
3499 }
3500
3501 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003502}
3503
3504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003505RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003506 NoHandleAllocation ha;
3507 ASSERT(args.length() == 2);
3508
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003509 CONVERT_ARG_CHECKED(String, str1, 0);
3510 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511
3512 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003513 int str1_length = str1->length();
3514 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003515
3516 // Decide trivial cases without flattening.
3517 if (str1_length == 0) {
3518 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3519 return Smi::FromInt(-str2_length);
3520 } else {
3521 if (str2_length == 0) return Smi::FromInt(str1_length);
3522 }
3523
3524 int end = str1_length < str2_length ? str1_length : str2_length;
3525
3526 // No need to flatten if we are going to find the answer on the first
3527 // character. At this point we know there is at least one character
3528 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003529 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003530 if (d != 0) return Smi::FromInt(d);
3531
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003532 str1->TryFlatten();
3533 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003534
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003535 StringInputBuffer& buf1 =
3536 *isolate->runtime_state()->string_locale_compare_buf1();
3537 StringInputBuffer& buf2 =
3538 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539
3540 buf1.Reset(str1);
3541 buf2.Reset(str2);
3542
3543 for (int i = 0; i < end; i++) {
3544 uint16_t char1 = buf1.GetNext();
3545 uint16_t char2 = buf2.GetNext();
3546 if (char1 != char2) return Smi::FromInt(char1 - char2);
3547 }
3548
3549 return Smi::FromInt(str1_length - str2_length);
3550}
3551
3552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003553RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 NoHandleAllocation ha;
3555 ASSERT(args.length() == 3);
3556
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003557 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003558 int start, end;
3559 // We have a fast integer-only case here to avoid a conversion to double in
3560 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003561 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3562 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3563 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3564 start = from_number;
3565 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003566 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003567 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3568 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003569 start = FastD2I(from_number);
3570 end = FastD2I(to_number);
3571 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 RUNTIME_ASSERT(end >= start);
3573 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003574 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003575 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003576 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003577}
3578
3579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003580RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003581 ASSERT_EQ(3, args.length());
3582
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003583 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3584 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3585 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003586 HandleScope handles;
3587
3588 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3589
3590 if (match.is_null()) {
3591 return Failure::Exception();
3592 }
3593 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003595 }
3596 int length = subject->length();
3597
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003598 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003599 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003600 int start;
3601 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003602 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003603 {
3604 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003605 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003606 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3607 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3608 }
3609 offsets.Add(start);
3610 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003611 if (start == end) if (++end > length) break;
3612 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003613 if (match.is_null()) {
3614 return Failure::Exception();
3615 }
3616 } while (!match->IsNull());
3617 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003619 Handle<String> substring = isolate->factory()->
3620 NewSubString(subject, offsets.at(0), offsets.at(1));
3621 elements->set(0, *substring);
3622 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003623 int from = offsets.at(i * 2);
3624 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003625 Handle<String> substring = isolate->factory()->
3626 NewProperSubString(subject, from, to);
3627 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003628 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003630 result->set_length(Smi::FromInt(matches));
3631 return *result;
3632}
3633
3634
lrn@chromium.org25156de2010-04-06 13:10:27 +00003635// Two smis before and after the match, for very long strings.
3636const int kMaxBuilderEntriesPerRegExpMatch = 5;
3637
3638
3639static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3640 Handle<JSArray> last_match_info,
3641 int match_start,
3642 int match_end) {
3643 // Fill last_match_info with a single capture.
3644 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3645 AssertNoAllocation no_gc;
3646 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3647 RegExpImpl::SetLastCaptureCount(elements, 2);
3648 RegExpImpl::SetLastInput(elements, *subject);
3649 RegExpImpl::SetLastSubject(elements, *subject);
3650 RegExpImpl::SetCapture(elements, 0, match_start);
3651 RegExpImpl::SetCapture(elements, 1, match_end);
3652}
3653
3654
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003655template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003656static bool SearchStringMultiple(Isolate* isolate,
3657 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003658 Vector<const PatternChar> pattern,
3659 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660 FixedArrayBuilder* builder,
3661 int* match_pos) {
3662 int pos = *match_pos;
3663 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003664 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003665 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003666 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003667 while (pos <= max_search_start) {
3668 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3669 *match_pos = pos;
3670 return false;
3671 }
3672 // Position of end of previous match.
3673 int match_end = pos + pattern_length;
3674 int new_pos = search.Search(subject, match_end);
3675 if (new_pos >= 0) {
3676 // A match.
3677 if (new_pos > match_end) {
3678 ReplacementStringBuilder::AddSubjectSlice(builder,
3679 match_end,
3680 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003681 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003682 pos = new_pos;
3683 builder->Add(pattern_string);
3684 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003685 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003686 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003688
lrn@chromium.org25156de2010-04-06 13:10:27 +00003689 if (pos < max_search_start) {
3690 ReplacementStringBuilder::AddSubjectSlice(builder,
3691 pos + pattern_length,
3692 subject_length);
3693 }
3694 *match_pos = pos;
3695 return true;
3696}
3697
3698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003699static bool SearchStringMultiple(Isolate* isolate,
3700 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003701 Handle<String> pattern,
3702 Handle<JSArray> last_match_info,
3703 FixedArrayBuilder* builder) {
3704 ASSERT(subject->IsFlat());
3705 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003706
3707 // Treating as if a previous match was before first character.
3708 int match_pos = -pattern->length();
3709
3710 for (;;) { // Break when search complete.
3711 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3712 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003713 String::FlatContent subject_content = subject->GetFlatContent();
3714 String::FlatContent pattern_content = pattern->GetFlatContent();
3715 if (subject_content.IsAscii()) {
3716 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3717 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 if (SearchStringMultiple(isolate,
3719 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003720 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003721 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003722 builder,
3723 &match_pos)) break;
3724 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 if (SearchStringMultiple(isolate,
3726 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003727 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003728 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003729 builder,
3730 &match_pos)) break;
3731 }
3732 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003733 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3734 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003735 if (SearchStringMultiple(isolate,
3736 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003737 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003738 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003739 builder,
3740 &match_pos)) break;
3741 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003742 if (SearchStringMultiple(isolate,
3743 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003744 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003745 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003746 builder,
3747 &match_pos)) break;
3748 }
3749 }
3750 }
3751
3752 if (match_pos >= 0) {
3753 SetLastMatchInfoNoCaptures(subject,
3754 last_match_info,
3755 match_pos,
3756 match_pos + pattern->length());
3757 return true;
3758 }
3759 return false; // No matches at all.
3760}
3761
3762
3763static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003764 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003765 Handle<String> subject,
3766 Handle<JSRegExp> regexp,
3767 Handle<JSArray> last_match_array,
3768 FixedArrayBuilder* builder) {
3769 ASSERT(subject->IsFlat());
3770 int match_start = -1;
3771 int match_end = 0;
3772 int pos = 0;
3773 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3774 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3775
ulan@chromium.org812308e2012-02-29 15:58:45 +00003776 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003777 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003778 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003779 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003780
3781 for (;;) { // Break on failure, return on exception.
3782 RegExpImpl::IrregexpResult result =
3783 RegExpImpl::IrregexpExecOnce(regexp,
3784 subject,
3785 pos,
3786 register_vector);
3787 if (result == RegExpImpl::RE_SUCCESS) {
3788 match_start = register_vector[0];
3789 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3790 if (match_end < match_start) {
3791 ReplacementStringBuilder::AddSubjectSlice(builder,
3792 match_end,
3793 match_start);
3794 }
3795 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003796 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003797 if (!first) {
3798 builder->Add(*isolate->factory()->NewProperSubString(subject,
3799 match_start,
3800 match_end));
3801 } else {
3802 builder->Add(*isolate->factory()->NewSubString(subject,
3803 match_start,
3804 match_end));
3805 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003806 if (match_start != match_end) {
3807 pos = match_end;
3808 } else {
3809 pos = match_end + 1;
3810 if (pos > subject_length) break;
3811 }
3812 } else if (result == RegExpImpl::RE_FAILURE) {
3813 break;
3814 } else {
3815 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3816 return result;
3817 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003818 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003819 }
3820
3821 if (match_start >= 0) {
3822 if (match_end < subject_length) {
3823 ReplacementStringBuilder::AddSubjectSlice(builder,
3824 match_end,
3825 subject_length);
3826 }
3827 SetLastMatchInfoNoCaptures(subject,
3828 last_match_array,
3829 match_start,
3830 match_end);
3831 return RegExpImpl::RE_SUCCESS;
3832 } else {
3833 return RegExpImpl::RE_FAILURE; // No matches at all.
3834 }
3835}
3836
3837
3838static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003839 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003840 Handle<String> subject,
3841 Handle<JSRegExp> regexp,
3842 Handle<JSArray> last_match_array,
3843 FixedArrayBuilder* builder) {
3844
3845 ASSERT(subject->IsFlat());
3846 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3847 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3848
ulan@chromium.org812308e2012-02-29 15:58:45 +00003849 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003850 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003851
3852 RegExpImpl::IrregexpResult result =
3853 RegExpImpl::IrregexpExecOnce(regexp,
3854 subject,
3855 0,
3856 register_vector);
3857
3858 int capture_count = regexp->CaptureCount();
3859 int subject_length = subject->length();
3860
3861 // Position to search from.
3862 int pos = 0;
3863 // End of previous match. Differs from pos if match was empty.
3864 int match_end = 0;
3865 if (result == RegExpImpl::RE_SUCCESS) {
3866 // Need to keep a copy of the previous match for creating last_match_info
3867 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003868 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003869 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003870 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003871 do {
3872 int match_start = register_vector[0];
3873 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3874 if (match_end < match_start) {
3875 ReplacementStringBuilder::AddSubjectSlice(builder,
3876 match_end,
3877 match_start);
3878 }
3879 match_end = register_vector[1];
3880
3881 {
3882 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003883 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003884 // Arguments array to replace function is match, captures, index and
3885 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003886 Handle<FixedArray> elements =
3887 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003888 Handle<String> match;
3889 if (!first) {
3890 match = isolate->factory()->NewProperSubString(subject,
3891 match_start,
3892 match_end);
3893 } else {
3894 match = isolate->factory()->NewSubString(subject,
3895 match_start,
3896 match_end);
3897 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003898 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003899 for (int i = 1; i <= capture_count; i++) {
3900 int start = register_vector[i * 2];
3901 if (start >= 0) {
3902 int end = register_vector[i * 2 + 1];
3903 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003904 Handle<String> substring;
3905 if (!first) {
3906 substring = isolate->factory()->NewProperSubString(subject,
3907 start,
3908 end);
3909 } else {
3910 substring = isolate->factory()->NewSubString(subject, start, end);
3911 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003912 elements->set(i, *substring);
3913 } else {
3914 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003915 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003916 }
3917 }
3918 elements->set(capture_count + 1, Smi::FromInt(match_start));
3919 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003920 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003921 }
3922 // Swap register vectors, so the last successful match is in
3923 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003924 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003925 prev_register_vector = register_vector;
3926 register_vector = tmp;
3927
3928 if (match_end > match_start) {
3929 pos = match_end;
3930 } else {
3931 pos = match_end + 1;
3932 if (pos > subject_length) {
3933 break;
3934 }
3935 }
3936
3937 result = RegExpImpl::IrregexpExecOnce(regexp,
3938 subject,
3939 pos,
3940 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003941 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003942 } while (result == RegExpImpl::RE_SUCCESS);
3943
3944 if (result != RegExpImpl::RE_EXCEPTION) {
3945 // Finished matching, with at least one match.
3946 if (match_end < subject_length) {
3947 ReplacementStringBuilder::AddSubjectSlice(builder,
3948 match_end,
3949 subject_length);
3950 }
3951
3952 int last_match_capture_count = (capture_count + 1) * 2;
3953 int last_match_array_size =
3954 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3955 last_match_array->EnsureSize(last_match_array_size);
3956 AssertNoAllocation no_gc;
3957 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3958 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3959 RegExpImpl::SetLastSubject(elements, *subject);
3960 RegExpImpl::SetLastInput(elements, *subject);
3961 for (int i = 0; i < last_match_capture_count; i++) {
3962 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3963 }
3964 return RegExpImpl::RE_SUCCESS;
3965 }
3966 }
3967 // No matches at all, return failure or exception result directly.
3968 return result;
3969}
3970
3971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003972RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003973 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003974 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003975
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003976 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003977 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003978 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3979 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3980 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003981
3982 ASSERT(last_match_info->HasFastElements());
3983 ASSERT(regexp->GetFlags().is_global());
3984 Handle<FixedArray> result_elements;
3985 if (result_array->HasFastElements()) {
3986 result_elements =
3987 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003988 }
3989 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003990 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003991 }
3992 FixedArrayBuilder builder(result_elements);
3993
3994 if (regexp->TypeTag() == JSRegExp::ATOM) {
3995 Handle<String> pattern(
3996 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003997 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998 if (SearchStringMultiple(isolate, subject, pattern,
3999 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004000 return *builder.ToJSArray(result_array);
4001 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004002 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004003 }
4004
4005 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4006
4007 RegExpImpl::IrregexpResult result;
4008 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 result = SearchRegExpNoCaptureMultiple(isolate,
4010 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004011 regexp,
4012 last_match_info,
4013 &builder);
4014 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004015 result = SearchRegExpMultiple(isolate,
4016 subject,
4017 regexp,
4018 last_match_info,
4019 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004020 }
4021 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004023 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4024 return Failure::Exception();
4025}
4026
4027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004028RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 NoHandleAllocation ha;
4030 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004031 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004032 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004034 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004035 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004036 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004037 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004038 // Character array used for conversion.
4039 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004040 return isolate->heap()->
4041 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004042 }
4043 }
4044
4045 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004046 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004048 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 }
4050 if (isinf(value)) {
4051 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004054 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004057 MaybeObject* result =
4058 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 DeleteArray(str);
4060 return result;
4061}
4062
4063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004064RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 NoHandleAllocation ha;
4066 ASSERT(args.length() == 2);
4067
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004068 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004070 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071 }
4072 if (isinf(value)) {
4073 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004076 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004078 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 int f = FastD2I(f_number);
4080 RUNTIME_ASSERT(f >= 0);
4081 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004082 MaybeObject* res =
4083 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004085 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086}
4087
4088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004089RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 NoHandleAllocation ha;
4091 ASSERT(args.length() == 2);
4092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004093 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004095 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 }
4097 if (isinf(value)) {
4098 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004099 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004101 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004103 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 int f = FastD2I(f_number);
4105 RUNTIME_ASSERT(f >= -1 && f <= 20);
4106 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004107 MaybeObject* res =
4108 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004110 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111}
4112
4113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004114RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 NoHandleAllocation ha;
4116 ASSERT(args.length() == 2);
4117
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004118 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004120 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 }
4122 if (isinf(value)) {
4123 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004124 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004126 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004128 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129 int f = FastD2I(f_number);
4130 RUNTIME_ASSERT(f >= 1 && f <= 21);
4131 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004132 MaybeObject* res =
4133 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004135 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136}
4137
4138
4139// Returns a single character string where first character equals
4140// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004141static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004142 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004143 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004144 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004145 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004147 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148}
4149
4150
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004151MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4152 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004153 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 // Handle [] indexing on Strings
4155 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004156 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4157 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 }
4159
4160 // Handle [] indexing on String objects
4161 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004162 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4163 Handle<Object> result =
4164 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4165 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 }
4167
4168 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004169 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 }
4171
4172 return object->GetElement(index);
4173}
4174
4175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4177 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004178 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004180
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004182 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004184 isolate->factory()->NewTypeError("non_object_property_load",
4185 HandleVector(args, 2));
4186 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188
4189 // Check if the given key is an array index.
4190 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004191 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004192 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 }
4194
4195 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004198 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 bool has_pending_exception = false;
4201 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004204 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 }
4206
ager@chromium.org32912102009-01-16 10:38:43 +00004207 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 // the element if so.
4209 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004210 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004212 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004213 }
4214}
4215
4216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 NoHandleAllocation ha;
4219 ASSERT(args.length() == 2);
4220
4221 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004222 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004224 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225}
4226
4227
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004228// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004229RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004230 NoHandleAllocation ha;
4231 ASSERT(args.length() == 2);
4232
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004233 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004234 // itself.
4235 //
4236 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004237 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004238 // global proxy object never has properties. This is the case
4239 // because the global proxy object forwards everything to its hidden
4240 // prototype including local lookups.
4241 //
4242 // Additionally, we need to make sure that we do not cache results
4243 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004244 if (args[0]->IsJSObject()) {
4245 if (!args[0]->IsJSGlobalProxy() &&
4246 !args[0]->IsAccessCheckNeeded() &&
4247 args[1]->IsString()) {
4248 JSObject* receiver = JSObject::cast(args[0]);
4249 String* key = String::cast(args[1]);
4250 if (receiver->HasFastProperties()) {
4251 // Attempt to use lookup cache.
4252 Map* receiver_map = receiver->map();
4253 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4254 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4255 if (offset != -1) {
4256 Object* value = receiver->FastPropertyAt(offset);
4257 return value->IsTheHole()
4258 ? isolate->heap()->undefined_value()
4259 : value;
4260 }
4261 // Lookup cache miss. Perform lookup and update the cache if
4262 // appropriate.
4263 LookupResult result(isolate);
4264 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004265 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004266 int offset = result.GetFieldIndex();
4267 keyed_lookup_cache->Update(receiver_map, key, offset);
4268 return receiver->FastPropertyAt(offset);
4269 }
4270 } else {
4271 // Attempt dictionary lookup.
4272 StringDictionary* dictionary = receiver->property_dictionary();
4273 int entry = dictionary->FindEntry(key);
4274 if ((entry != StringDictionary::kNotFound) &&
4275 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4276 Object* value = dictionary->ValueAt(entry);
4277 if (!receiver->IsGlobalObject()) return value;
4278 value = JSGlobalPropertyCell::cast(value)->value();
4279 if (!value->IsTheHole()) return value;
4280 // If value is the hole do the general lookup.
4281 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004282 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004283 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4284 // JSObject without a string key. If the key is a Smi, check for a
4285 // definite out-of-bounds access to elements, which is a strong indicator
4286 // that subsequent accesses will also call the runtime. Proactively
4287 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4288 // doubles for those future calls in the case that the elements would
4289 // become FAST_DOUBLE_ELEMENTS.
4290 Handle<JSObject> js_object(args.at<JSObject>(0));
4291 ElementsKind elements_kind = js_object->GetElementsKind();
4292 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4293 elements_kind == FAST_DOUBLE_ELEMENTS) {
4294 FixedArrayBase* elements = js_object->elements();
4295 if (args.at<Smi>(1)->value() >= elements->length()) {
4296 MaybeObject* maybe_object = TransitionElements(js_object,
4297 FAST_ELEMENTS,
4298 isolate);
4299 if (maybe_object->IsFailure()) return maybe_object;
4300 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004301 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004302 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004303 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4304 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004306 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004307 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004308 if (index >= 0 && index < str->length()) {
4309 Handle<Object> result = GetCharAt(str, index);
4310 return *result;
4311 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004312 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004313
4314 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004315 return Runtime::GetObjectProperty(isolate,
4316 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004317 args.at<Object>(1));
4318}
4319
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004320
4321static bool IsValidAccessor(Handle<Object> obj) {
4322 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4323}
4324
4325
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004326// Implements part of 8.12.9 DefineOwnProperty.
4327// There are 3 cases that lead here:
4328// Step 4b - define a new accessor property.
4329// Steps 9c & 12 - replace an existing data property with an accessor property.
4330// Step 12 - update an existing accessor property with an accessor or generic
4331// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004332RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004333 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004334 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004335 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004336 RUNTIME_ASSERT(!obj->IsNull());
4337 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4338 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4339 RUNTIME_ASSERT(IsValidAccessor(getter));
4340 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4341 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004342 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004343 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004344 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004345
danno@chromium.org88aa0582012-03-23 15:11:57 +00004346 bool fast = obj->HasFastProperties();
4347 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4348 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004349 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004350}
4351
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004352// Implements part of 8.12.9 DefineOwnProperty.
4353// There are 3 cases that lead here:
4354// Step 4a - define a new data property.
4355// Steps 9b & 12 - replace an existing accessor property with a data property.
4356// Step 12 - update an existing data property with a data or generic
4357// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004358RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004359 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004360 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004361 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4362 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004363 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004364 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004365 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004366 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4367
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004368 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004369 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004370
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004371 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004372 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004373 Object* callback = result.GetCallbackObject();
4374 // To be compatible with Safari we do not change the value on API objects
4375 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4376 // the value.
4377 if (callback->IsAccessorInfo()) {
4378 return isolate->heap()->undefined_value();
4379 }
4380 // Avoid redefining foreign callback as data property, just use the stored
4381 // setter to update the value instead.
4382 // TODO(mstarzinger): So far this only works if property attributes don't
4383 // change, this should be fixed once we cleanup the underlying code.
4384 if (callback->IsForeign() && result.GetAttributes() == attr) {
4385 return js_object->SetPropertyWithCallback(callback,
4386 *name,
4387 *obj_value,
4388 result.holder(),
4389 kStrictMode);
4390 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004391 }
4392
ager@chromium.org5c838252010-02-19 08:53:10 +00004393 // Take special care when attributes are different and there is already
4394 // a property. For simplicity we normalize the property which enables us
4395 // to not worry about changing the instance_descriptor and creating a new
4396 // map. The current version of SetObjectProperty does not handle attributes
4397 // correctly in the case where a property is a field and is reset with
4398 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004399 if (result.IsProperty() &&
4400 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004401 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004402 if (js_object->IsJSGlobalProxy()) {
4403 // Since the result is a property, the prototype will exist so
4404 // we don't have to check for null.
4405 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004406 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004407 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004408 // Use IgnoreAttributes version since a readonly property may be
4409 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004410 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4411 *obj_value,
4412 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004413 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004415 return Runtime::ForceSetObjectProperty(isolate,
4416 js_object,
4417 name,
4418 obj_value,
4419 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004420}
4421
4422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004423MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4424 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004425 Handle<Object> key,
4426 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004427 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004428 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004429 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004432 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004433 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004435 isolate->factory()->NewTypeError("non_object_property_store",
4436 HandleVector(args, 2));
4437 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 }
4439
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004440 if (object->IsJSProxy()) {
4441 bool has_pending_exception = false;
4442 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4443 if (has_pending_exception) return Failure::Exception();
4444 return JSProxy::cast(*object)->SetProperty(
4445 String::cast(*name), *value, attr, strict_mode);
4446 }
4447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 // If the object isn't a JavaScript object, we ignore the store.
4449 if (!object->IsJSObject()) return *value;
4450
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004451 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453 // Check if the given key is an array index.
4454 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004455 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4457 // of a string using [] notation. We need to support this too in
4458 // JavaScript.
4459 // In the case of a String object we just need to redirect the assignment to
4460 // the underlying string if the index is in range. Since the underlying
4461 // string does nothing with the assignment then we can ignore such
4462 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004463 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004464 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004467 Handle<Object> result = JSObject::SetElement(
4468 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004469 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 return *value;
4471 }
4472
4473 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004474 Handle<Object> result;
4475 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004476 result = JSObject::SetElement(
4477 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004479 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004480 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004481 result = JSReceiver::SetProperty(
4482 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 return *value;
4486 }
4487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 bool has_pending_exception = false;
4490 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4491 if (has_pending_exception) return Failure::Exception();
4492 Handle<String> name = Handle<String>::cast(converted);
4493
4494 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004495 return js_object->SetElement(
4496 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004498 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 }
4500}
4501
4502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004503MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4504 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004505 Handle<Object> key,
4506 Handle<Object> value,
4507 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004508 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004509
4510 // Check if the given key is an array index.
4511 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004512 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004513 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4514 // of a string using [] notation. We need to support this too in
4515 // JavaScript.
4516 // In the case of a String object we just need to redirect the assignment to
4517 // the underlying string if the index is in range. Since the underlying
4518 // string does nothing with the assignment then we can ignore such
4519 // assignments.
4520 if (js_object->IsStringObjectWithCharacterAt(index)) {
4521 return *value;
4522 }
4523
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004524 return js_object->SetElement(
4525 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004526 }
4527
4528 if (key->IsString()) {
4529 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004530 return js_object->SetElement(
4531 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004532 } else {
4533 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004534 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004535 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4536 *value,
4537 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004538 }
4539 }
4540
4541 // Call-back into JavaScript to convert the key to a string.
4542 bool has_pending_exception = false;
4543 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4544 if (has_pending_exception) return Failure::Exception();
4545 Handle<String> name = Handle<String>::cast(converted);
4546
4547 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004548 return js_object->SetElement(
4549 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004550 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004551 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004552 }
4553}
4554
4555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004556MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004557 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004559 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004560
4561 // Check if the given key is an array index.
4562 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004563 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004564 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4565 // characters of a string using [] notation. In the case of a
4566 // String object we just need to redirect the deletion to the
4567 // underlying string if the index is in range. Since the
4568 // underlying string does nothing with the deletion, we can ignore
4569 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004570 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004571 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004572 }
4573
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004574 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004575 }
4576
4577 Handle<String> key_string;
4578 if (key->IsString()) {
4579 key_string = Handle<String>::cast(key);
4580 } else {
4581 // Call-back into JavaScript to convert the key to a string.
4582 bool has_pending_exception = false;
4583 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4584 if (has_pending_exception) return Failure::Exception();
4585 key_string = Handle<String>::cast(converted);
4586 }
4587
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004588 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004589 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004590}
4591
4592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004593RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004595 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596
4597 Handle<Object> object = args.at<Object>(0);
4598 Handle<Object> key = args.at<Object>(1);
4599 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004600 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004601 RUNTIME_ASSERT(
4602 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004604 PropertyAttributes attributes =
4605 static_cast<PropertyAttributes>(unchecked_attributes);
4606
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004607 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004608 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004609 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004610 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004613 return Runtime::SetObjectProperty(isolate,
4614 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004615 key,
4616 value,
4617 attributes,
4618 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619}
4620
4621
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004622RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4623 NoHandleAllocation ha;
4624 RUNTIME_ASSERT(args.length() == 1);
4625 Handle<Object> object = args.at<Object>(0);
4626 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4627}
4628
4629
4630RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4631 NoHandleAllocation ha;
4632 RUNTIME_ASSERT(args.length() == 1);
4633 Handle<Object> object = args.at<Object>(0);
4634 return TransitionElements(object, FAST_ELEMENTS, isolate);
4635}
4636
4637
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004638// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004639// This is used to decide if we should transform null and undefined
4640// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004641RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004642 NoHandleAllocation ha;
4643 RUNTIME_ASSERT(args.length() == 1);
4644
4645 Handle<Object> object = args.at<Object>(0);
4646
4647 if (object->IsJSFunction()) {
4648 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004649 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004650 }
4651 return isolate->heap()->undefined_value();
4652}
4653
4654
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004655RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4656 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004657 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004658 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4659 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004660 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004661 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4662 HandleScope scope;
4663
4664 Object* raw_boilerplate_object = literals->get(literal_index);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004665 Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004666#if DEBUG
4667 ElementsKind elements_kind = object->GetElementsKind();
4668#endif
4669 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4670 // Smis should never trigger transitions.
4671 ASSERT(!value->IsSmi());
4672
4673 if (value->IsNumber()) {
4674 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004675 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004676 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4677 FAST_DOUBLE_ELEMENTS)) {
4678 JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS);
4679 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004680 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004681 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004682 HeapNumber* number = HeapNumber::cast(*value);
4683 double_array->set(store_index, number->Number());
4684 } else {
4685 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4686 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004687 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004688 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4689 FAST_ELEMENTS)) {
4690 JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS);
4691 }
4692 FixedArray* object_array = FixedArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004693 object_array->set(store_index, *value);
4694 }
4695 return *object;
4696}
4697
4698
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004699// Set a local property, even if it is READ_ONLY. If the property does not
4700// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004701RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004703 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004704 CONVERT_ARG_CHECKED(JSObject, object, 0);
4705 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004706 // Compute attributes.
4707 PropertyAttributes attributes = NONE;
4708 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004709 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004710 // Only attribute bits should be set.
4711 RUNTIME_ASSERT(
4712 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4713 attributes = static_cast<PropertyAttributes>(unchecked_value);
4714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004716 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004717 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718}
4719
4720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004721RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004723 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004725 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4726 CONVERT_ARG_CHECKED(String, key, 1);
4727 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004728 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004729 ? JSReceiver::STRICT_DELETION
4730 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731}
4732
4733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004734static Object* HasLocalPropertyImplementation(Isolate* isolate,
4735 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004736 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004738 // Handle hidden prototypes. If there's a hidden prototype above this thing
4739 // then we have to check it for properties, because they are supposed to
4740 // look like they are on this object.
4741 Handle<Object> proto(object->GetPrototype());
4742 if (proto->IsJSObject() &&
4743 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004744 return HasLocalPropertyImplementation(isolate,
4745 Handle<JSObject>::cast(proto),
4746 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004747 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004749}
4750
4751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004752RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 NoHandleAllocation ha;
4754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004755 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004757 uint32_t index;
4758 const bool key_is_array_index = key->AsArrayIndex(&index);
4759
ager@chromium.org9085a012009-05-11 19:22:57 +00004760 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004762 if (obj->IsJSObject()) {
4763 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004764 // Fast case: either the key is a real named property or it is not
4765 // an array index and there are no interceptors or hidden
4766 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004767 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004768 Map* map = object->map();
4769 if (!key_is_array_index &&
4770 !map->has_named_interceptor() &&
4771 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4772 return isolate->heap()->false_value();
4773 }
4774 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004775 HandleScope scope(isolate);
4776 return HasLocalPropertyImplementation(isolate,
4777 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004778 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004779 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004781 String* string = String::cast(obj);
4782 if (index < static_cast<uint32_t>(string->length())) {
4783 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784 }
4785 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004786 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787}
4788
4789
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004790RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791 NoHandleAllocation na;
4792 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004793 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4794 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004796 bool result = receiver->HasProperty(key);
4797 if (isolate->has_pending_exception()) return Failure::Exception();
4798 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004799}
4800
4801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004802RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803 NoHandleAllocation na;
4804 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004805 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4806 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004808 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004809 if (isolate->has_pending_exception()) return Failure::Exception();
4810 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811}
4812
4813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004814RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004815 NoHandleAllocation ha;
4816 ASSERT(args.length() == 2);
4817
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004818 CONVERT_ARG_CHECKED(JSObject, object, 0);
4819 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820
4821 uint32_t index;
4822 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004823 JSObject::LocalElementType type = object->HasLocalElement(index);
4824 switch (type) {
4825 case JSObject::UNDEFINED_ELEMENT:
4826 case JSObject::STRING_CHARACTER_ELEMENT:
4827 return isolate->heap()->false_value();
4828 case JSObject::INTERCEPTED_ELEMENT:
4829 case JSObject::FAST_ELEMENT:
4830 return isolate->heap()->true_value();
4831 case JSObject::DICTIONARY_ELEMENT: {
4832 if (object->IsJSGlobalProxy()) {
4833 Object* proto = object->GetPrototype();
4834 if (proto->IsNull()) {
4835 return isolate->heap()->false_value();
4836 }
4837 ASSERT(proto->IsJSGlobalObject());
4838 object = JSObject::cast(proto);
4839 }
4840 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004841 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004842 if (elements->map() ==
4843 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004844 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004845 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004846 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004847 }
4848 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004849 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004850 PropertyDetails details = dictionary->DetailsAt(entry);
4851 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4852 }
4853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854 }
4855
ager@chromium.org870a0b62008-11-04 11:43:05 +00004856 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004857 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858}
4859
4860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004861RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004862 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004863 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004864 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004865 bool threw = false;
4866 Handle<JSArray> result = GetKeysFor(object, &threw);
4867 if (threw) return Failure::Exception();
4868 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869}
4870
4871
4872// Returns either a FixedArray as Runtime_GetPropertyNames,
4873// or, if the given object has an enum cache that contains
4874// all enumerable properties of the object and its prototypes
4875// have none, the map of the object. This is used to speed up
4876// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004877RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 ASSERT(args.length() == 1);
4879
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004880 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881
4882 if (raw_object->IsSimpleEnum()) return raw_object->map();
4883
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004884 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004885 Handle<JSReceiver> object(raw_object);
4886 bool threw = false;
4887 Handle<FixedArray> content =
4888 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4889 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890
4891 // Test again, since cache may have been built by preceding call.
4892 if (object->IsSimpleEnum()) return object->map();
4893
4894 return *content;
4895}
4896
4897
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004898// Find the length of the prototype chain that is to to handled as one. If a
4899// prototype object is hidden it is to be viewed as part of the the object it
4900// is prototype for.
4901static int LocalPrototypeChainLength(JSObject* obj) {
4902 int count = 1;
4903 Object* proto = obj->GetPrototype();
4904 while (proto->IsJSObject() &&
4905 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4906 count++;
4907 proto = JSObject::cast(proto)->GetPrototype();
4908 }
4909 return count;
4910}
4911
4912
4913// Return the names of the local named properties.
4914// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004915RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004917 ASSERT(args.length() == 1);
4918 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004919 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004920 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004921 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004922
4923 // Skip the global proxy as it has no properties and always delegates to the
4924 // real global object.
4925 if (obj->IsJSGlobalProxy()) {
4926 // Only collect names if access is permitted.
4927 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004928 !isolate->MayNamedAccess(*obj,
4929 isolate->heap()->undefined_value(),
4930 v8::ACCESS_KEYS)) {
4931 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4932 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004933 }
4934 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4935 }
4936
4937 // Find the number of objects making up this.
4938 int length = LocalPrototypeChainLength(*obj);
4939
4940 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004941 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004942 int total_property_count = 0;
4943 Handle<JSObject> jsproto = obj;
4944 for (int i = 0; i < length; i++) {
4945 // Only collect names if access is permitted.
4946 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004947 !isolate->MayNamedAccess(*jsproto,
4948 isolate->heap()->undefined_value(),
4949 v8::ACCESS_KEYS)) {
4950 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4951 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004952 }
4953 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004954 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004955 local_property_count[i] = n;
4956 total_property_count += n;
4957 if (i < length - 1) {
4958 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4959 }
4960 }
4961
4962 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004963 Handle<FixedArray> names =
4964 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004965
4966 // Get the property names.
4967 jsproto = obj;
4968 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004969 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004970 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004971 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4972 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004973 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004974 proto_with_hidden_properties++;
4975 }
4976 if (i < length - 1) {
4977 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4978 }
4979 }
4980
4981 // Filter out name of hidden propeties object.
4982 if (proto_with_hidden_properties > 0) {
4983 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 names->length() - proto_with_hidden_properties);
4986 int dest_pos = 0;
4987 for (int i = 0; i < total_property_count; i++) {
4988 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004989 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004990 continue;
4991 }
4992 names->set(dest_pos++, name);
4993 }
4994 }
4995
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004996 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004997}
4998
4999
5000// Return the names of the local indexed properties.
5001// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005002RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005004 ASSERT(args.length() == 1);
5005 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005007 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005008 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005009
5010 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005011 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005012 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005013 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005014}
5015
5016
5017// Return information on whether an object has a named or indexed interceptor.
5018// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005019RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005020 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005021 ASSERT(args.length() == 1);
5022 if (!args[0]->IsJSObject()) {
5023 return Smi::FromInt(0);
5024 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005025 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005026
5027 int result = 0;
5028 if (obj->HasNamedInterceptor()) result |= 2;
5029 if (obj->HasIndexedInterceptor()) result |= 1;
5030
5031 return Smi::FromInt(result);
5032}
5033
5034
5035// Return property names from named interceptor.
5036// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005037RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005039 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005040 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005041
5042 if (obj->HasNamedInterceptor()) {
5043 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5044 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5045 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005047}
5048
5049
5050// Return element names from indexed interceptor.
5051// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005052RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005054 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005055 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005056
5057 if (obj->HasIndexedInterceptor()) {
5058 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5059 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5060 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005061 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005062}
5063
5064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005065RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005066 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005067 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005069 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005070
5071 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005072 // Do access checks before going to the global object.
5073 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005075 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005076 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5077 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005078 }
5079
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005080 Handle<Object> proto(object->GetPrototype());
5081 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005082 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005083 object = Handle<JSObject>::cast(proto);
5084 }
5085
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005086 bool threw = false;
5087 Handle<FixedArray> contents =
5088 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5089 if (threw) return Failure::Exception();
5090
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005091 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5092 // property array and since the result is mutable we have to create
5093 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005094 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005095 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005096 for (int i = 0; i < length; i++) {
5097 Object* entry = contents->get(i);
5098 if (entry->IsString()) {
5099 copy->set(i, entry);
5100 } else {
5101 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102 HandleScope scope(isolate);
5103 Handle<Object> entry_handle(entry, isolate);
5104 Handle<Object> entry_str =
5105 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005106 copy->set(i, *entry_str);
5107 }
5108 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005109 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005110}
5111
5112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005113RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 NoHandleAllocation ha;
5115 ASSERT(args.length() == 1);
5116
5117 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005118 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119 it.AdvanceToArgumentsFrame();
5120 JavaScriptFrame* frame = it.frame();
5121
5122 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005123 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124
5125 // Try to convert the key to an index. If successful and within
5126 // index return the the argument from the frame.
5127 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005128 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005129 return frame->GetParameter(index);
5130 }
5131
5132 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005133 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005134 bool exception = false;
5135 Handle<Object> converted =
5136 Execution::ToString(args.at<Object>(0), &exception);
5137 if (exception) return Failure::Exception();
5138 Handle<String> key = Handle<String>::cast(converted);
5139
5140 // Try to convert the string key into an array index.
5141 if (key->AsArrayIndex(&index)) {
5142 if (index < n) {
5143 return frame->GetParameter(index);
5144 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005145 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005146 }
5147 }
5148
5149 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005150 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5151 if (key->Equals(isolate->heap()->callee_symbol())) {
5152 Object* function = frame->function();
5153 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005154 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005155 return isolate->Throw(*isolate->factory()->NewTypeError(
5156 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5157 }
5158 return function;
5159 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005160
5161 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005162 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163}
5164
5165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005166RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005167 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005168 Object* object = args[0];
5169 return (object->IsJSObject() && !object->IsGlobalObject())
5170 ? JSObject::cast(object)->TransformToFastProperties(0)
5171 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005172}
5173
5174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005175RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005176 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005177 Object* obj = args[0];
5178 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5179 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5180 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005181}
5182
5183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005184RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185 NoHandleAllocation ha;
5186 ASSERT(args.length() == 1);
5187
5188 return args[0]->ToBoolean();
5189}
5190
5191
5192// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5193// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005194RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 NoHandleAllocation ha;
5196
5197 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005198 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199 HeapObject* heap_obj = HeapObject::cast(obj);
5200
5201 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005202 if (heap_obj->map()->is_undetectable()) {
5203 return isolate->heap()->undefined_symbol();
5204 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205
5206 InstanceType instance_type = heap_obj->map()->instance_type();
5207 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005209 }
5210
5211 switch (instance_type) {
5212 case ODDBALL_TYPE:
5213 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005214 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215 }
5216 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005217 return FLAG_harmony_typeof
5218 ? isolate->heap()->null_symbol()
5219 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 }
5221 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005223 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005224 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 default:
5227 // For any kind of object not handled above, the spec rule for
5228 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 }
5231}
5232
5233
lrn@chromium.org25156de2010-04-06 13:10:27 +00005234static bool AreDigits(const char*s, int from, int to) {
5235 for (int i = from; i < to; i++) {
5236 if (s[i] < '0' || s[i] > '9') return false;
5237 }
5238
5239 return true;
5240}
5241
5242
5243static int ParseDecimalInteger(const char*s, int from, int to) {
5244 ASSERT(to - from < 10); // Overflow is not possible.
5245 ASSERT(from < to);
5246 int d = s[from] - '0';
5247
5248 for (int i = from + 1; i < to; i++) {
5249 d = 10 * d + (s[i] - '0');
5250 }
5251
5252 return d;
5253}
5254
5255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005256RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257 NoHandleAllocation ha;
5258 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005259 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005260 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005261
5262 // Fast case: short integer or some sorts of junk values.
5263 int len = subject->length();
5264 if (subject->IsSeqAsciiString()) {
5265 if (len == 0) return Smi::FromInt(0);
5266
5267 char const* data = SeqAsciiString::cast(subject)->GetChars();
5268 bool minus = (data[0] == '-');
5269 int start_pos = (minus ? 1 : 0);
5270
5271 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005273 } else if (data[start_pos] > '9') {
5274 // Fast check for a junk value. A valid string may start from a
5275 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5276 // the 'I' character ('Infinity'). All of that have codes not greater than
5277 // '9' except 'I'.
5278 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005279 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005280 }
5281 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5282 // The maximal/minimal smi has 10 digits. If the string has less digits we
5283 // know it will fit into the smi-data type.
5284 int d = ParseDecimalInteger(data, start_pos, len);
5285 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005286 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005287 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005288 } else if (!subject->HasHashCode() &&
5289 len <= String::kMaxArrayIndexSize &&
5290 (len == 1 || data[0] != '0')) {
5291 // String hash is not calculated yet but all the data are present.
5292 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005293 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005294#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005295 subject->Hash(); // Force hash calculation.
5296 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5297 static_cast<int>(hash));
5298#endif
5299 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005300 }
5301 return Smi::FromInt(d);
5302 }
5303 }
5304
5305 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005306 return isolate->heap()->NumberFromDouble(
5307 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005308}
5309
5310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005311RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312 NoHandleAllocation ha;
5313 ASSERT(args.length() == 1);
5314
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005315 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005316 int length = Smi::cast(codes->length())->value();
5317
5318 // Check if the string can be ASCII.
5319 int i;
5320 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005321 Object* element;
5322 { MaybeObject* maybe_element = codes->GetElement(i);
5323 // We probably can't get an exception here, but just in order to enforce
5324 // the checking of inputs in the runtime calls we check here.
5325 if (!maybe_element->ToObject(&element)) return maybe_element;
5326 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5328 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5329 break;
5330 }
5331
lrn@chromium.org303ada72010-10-27 09:33:13 +00005332 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005334 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005335 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005336 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005337 }
5338
lrn@chromium.org303ada72010-10-27 09:33:13 +00005339 Object* object = NULL;
5340 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005341 String* result = String::cast(object);
5342 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005343 Object* element;
5344 { MaybeObject* maybe_element = codes->GetElement(i);
5345 if (!maybe_element->ToObject(&element)) return maybe_element;
5346 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005347 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005348 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005349 }
5350 return result;
5351}
5352
5353
5354// kNotEscaped is generated by the following:
5355//
5356// #!/bin/perl
5357// for (my $i = 0; $i < 256; $i++) {
5358// print "\n" if $i % 16 == 0;
5359// my $c = chr($i);
5360// my $escaped = 1;
5361// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5362// print $escaped ? "0, " : "1, ";
5363// }
5364
5365
5366static bool IsNotEscaped(uint16_t character) {
5367 // Only for 8 bit characters, the rest are always escaped (in a different way)
5368 ASSERT(character < 256);
5369 static const char kNotEscaped[256] = {
5370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5373 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5375 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5376 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5386 };
5387 return kNotEscaped[character] != 0;
5388}
5389
5390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005391RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 const char hex_chars[] = "0123456789ABCDEF";
5393 NoHandleAllocation ha;
5394 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005395 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005397 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398
5399 int escaped_length = 0;
5400 int length = source->length();
5401 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005402 Access<StringInputBuffer> buffer(
5403 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404 buffer->Reset(source);
5405 while (buffer->has_more()) {
5406 uint16_t character = buffer->GetNext();
5407 if (character >= 256) {
5408 escaped_length += 6;
5409 } else if (IsNotEscaped(character)) {
5410 escaped_length++;
5411 } else {
5412 escaped_length += 3;
5413 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005414 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005415 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005416 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005417 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418 return Failure::OutOfMemoryException();
5419 }
5420 }
5421 }
5422 // No length change implies no change. Return original string if no change.
5423 if (escaped_length == length) {
5424 return source;
5425 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005426 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005427 { MaybeObject* maybe_o =
5428 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005429 if (!maybe_o->ToObject(&o)) return maybe_o;
5430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 String* destination = String::cast(o);
5432 int dest_position = 0;
5433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005434 Access<StringInputBuffer> buffer(
5435 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005436 buffer->Rewind();
5437 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005438 uint16_t chr = buffer->GetNext();
5439 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005440 destination->Set(dest_position, '%');
5441 destination->Set(dest_position+1, 'u');
5442 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5443 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5444 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5445 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005446 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005447 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005448 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449 dest_position++;
5450 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005451 destination->Set(dest_position, '%');
5452 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5453 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005454 dest_position += 3;
5455 }
5456 }
5457 return destination;
5458}
5459
5460
5461static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5462 static const signed char kHexValue['g'] = {
5463 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5464 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5465 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5466 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5467 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5468 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5469 -1, 10, 11, 12, 13, 14, 15 };
5470
5471 if (character1 > 'f') return -1;
5472 int hi = kHexValue[character1];
5473 if (hi == -1) return -1;
5474 if (character2 > 'f') return -1;
5475 int lo = kHexValue[character2];
5476 if (lo == -1) return -1;
5477 return (hi << 4) + lo;
5478}
5479
5480
ager@chromium.org870a0b62008-11-04 11:43:05 +00005481static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005482 int i,
5483 int length,
5484 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005485 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005486 int32_t hi = 0;
5487 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005488 if (character == '%' &&
5489 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005490 source->Get(i + 1) == 'u' &&
5491 (hi = TwoDigitHex(source->Get(i + 2),
5492 source->Get(i + 3))) != -1 &&
5493 (lo = TwoDigitHex(source->Get(i + 4),
5494 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495 *step = 6;
5496 return (hi << 8) + lo;
5497 } else if (character == '%' &&
5498 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005499 (lo = TwoDigitHex(source->Get(i + 1),
5500 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 *step = 3;
5502 return lo;
5503 } else {
5504 *step = 1;
5505 return character;
5506 }
5507}
5508
5509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005510RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 NoHandleAllocation ha;
5512 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005513 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005515 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005516
5517 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005518 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519
5520 int unescaped_length = 0;
5521 for (int i = 0; i < length; unescaped_length++) {
5522 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005523 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005525 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005526 i += step;
5527 }
5528
5529 // No length change implies no change. Return original string if no change.
5530 if (unescaped_length == length)
5531 return source;
5532
lrn@chromium.org303ada72010-10-27 09:33:13 +00005533 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005534 { MaybeObject* maybe_o =
5535 ascii ?
5536 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5537 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005538 if (!maybe_o->ToObject(&o)) return maybe_o;
5539 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005540 String* destination = String::cast(o);
5541
5542 int dest_position = 0;
5543 for (int i = 0; i < length; dest_position++) {
5544 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005545 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005546 i += step;
5547 }
5548 return destination;
5549}
5550
5551
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005552static const unsigned int kQuoteTableLength = 128u;
5553
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005554static const int kJsonQuotesCharactersPerEntry = 8;
5555static const char* const JsonQuotes =
5556 "\\u0000 \\u0001 \\u0002 \\u0003 "
5557 "\\u0004 \\u0005 \\u0006 \\u0007 "
5558 "\\b \\t \\n \\u000b "
5559 "\\f \\r \\u000e \\u000f "
5560 "\\u0010 \\u0011 \\u0012 \\u0013 "
5561 "\\u0014 \\u0015 \\u0016 \\u0017 "
5562 "\\u0018 \\u0019 \\u001a \\u001b "
5563 "\\u001c \\u001d \\u001e \\u001f "
5564 " ! \\\" # "
5565 "$ % & ' "
5566 "( ) * + "
5567 ", - . / "
5568 "0 1 2 3 "
5569 "4 5 6 7 "
5570 "8 9 : ; "
5571 "< = > ? "
5572 "@ A B C "
5573 "D E F G "
5574 "H I J K "
5575 "L M N O "
5576 "P Q R S "
5577 "T U V W "
5578 "X Y Z [ "
5579 "\\\\ ] ^ _ "
5580 "` a b c "
5581 "d e f g "
5582 "h i j k "
5583 "l m n o "
5584 "p q r s "
5585 "t u v w "
5586 "x y z { "
5587 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005588
5589
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005590// For a string that is less than 32k characters it should always be
5591// possible to allocate it in new space.
5592static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5593
5594
5595// Doing JSON quoting cannot make the string more than this many times larger.
5596static const int kJsonQuoteWorstCaseBlowup = 6;
5597
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005598static const int kSpaceForQuotesAndComma = 3;
5599static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005600
5601// Covers the entire ASCII range (all other characters are unchanged by JSON
5602// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005603static const byte JsonQuoteLengths[kQuoteTableLength] = {
5604 6, 6, 6, 6, 6, 6, 6, 6,
5605 2, 2, 2, 6, 2, 2, 6, 6,
5606 6, 6, 6, 6, 6, 6, 6, 6,
5607 6, 6, 6, 6, 6, 6, 6, 6,
5608 1, 1, 2, 1, 1, 1, 1, 1,
5609 1, 1, 1, 1, 1, 1, 1, 1,
5610 1, 1, 1, 1, 1, 1, 1, 1,
5611 1, 1, 1, 1, 1, 1, 1, 1,
5612 1, 1, 1, 1, 1, 1, 1, 1,
5613 1, 1, 1, 1, 1, 1, 1, 1,
5614 1, 1, 1, 1, 1, 1, 1, 1,
5615 1, 1, 1, 1, 2, 1, 1, 1,
5616 1, 1, 1, 1, 1, 1, 1, 1,
5617 1, 1, 1, 1, 1, 1, 1, 1,
5618 1, 1, 1, 1, 1, 1, 1, 1,
5619 1, 1, 1, 1, 1, 1, 1, 1,
5620};
5621
5622
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005623template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005624MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005625
5626
5627template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005628MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5629 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005630}
5631
5632
5633template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005634MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5635 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005636}
5637
5638
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005639template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005640static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5641 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005642 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643 const Char* read_cursor = characters.start();
5644 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005645 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005646 int quoted_length = kSpaceForQuotes;
5647 while (read_cursor < end) {
5648 Char c = *(read_cursor++);
5649 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5650 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005651 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005652 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005653 }
5654 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005655 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5656 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005657 Object* new_object;
5658 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005659 return new_alloc;
5660 }
5661 StringType* new_string = StringType::cast(new_object);
5662
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005663 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005664 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005665 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005666 *(write_cursor++) = '"';
5667
5668 read_cursor = characters.start();
5669 while (read_cursor < end) {
5670 Char c = *(read_cursor++);
5671 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5672 *(write_cursor++) = c;
5673 } else {
5674 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5675 const char* replacement = JsonQuotes +
5676 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5677 for (int i = 0; i < len; i++) {
5678 *write_cursor++ = *replacement++;
5679 }
5680 }
5681 }
5682 *(write_cursor++) = '"';
5683 return new_string;
5684}
5685
5686
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005687template <typename SinkChar, typename SourceChar>
5688static inline SinkChar* WriteQuoteJsonString(
5689 Isolate* isolate,
5690 SinkChar* write_cursor,
5691 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005692 // SinkChar is only char if SourceChar is guaranteed to be char.
5693 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005694 const SourceChar* read_cursor = characters.start();
5695 const SourceChar* end = read_cursor + characters.length();
5696 *(write_cursor++) = '"';
5697 while (read_cursor < end) {
5698 SourceChar c = *(read_cursor++);
5699 if (sizeof(SourceChar) > 1u &&
5700 static_cast<unsigned>(c) >= kQuoteTableLength) {
5701 *(write_cursor++) = static_cast<SinkChar>(c);
5702 } else {
5703 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5704 const char* replacement = JsonQuotes +
5705 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5706 write_cursor[0] = replacement[0];
5707 if (len > 1) {
5708 write_cursor[1] = replacement[1];
5709 if (len > 2) {
5710 ASSERT(len == 6);
5711 write_cursor[2] = replacement[2];
5712 write_cursor[3] = replacement[3];
5713 write_cursor[4] = replacement[4];
5714 write_cursor[5] = replacement[5];
5715 }
5716 }
5717 write_cursor += len;
5718 }
5719 }
5720 *(write_cursor++) = '"';
5721 return write_cursor;
5722}
5723
5724
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005725template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005726static MaybeObject* QuoteJsonString(Isolate* isolate,
5727 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005728 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005730 int worst_case_length =
5731 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005732 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005734 }
5735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5737 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005738 Object* new_object;
5739 if (!new_alloc->ToObject(&new_object)) {
5740 return new_alloc;
5741 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005742 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005743 // Even if our string is small enough to fit in new space we still have to
5744 // handle it being allocated in old space as may happen in the third
5745 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5746 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005747 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005748 }
5749 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005750 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005751
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005752 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005753 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005754 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005755 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5756 write_cursor,
5757 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005758 int final_length = static_cast<int>(
5759 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005760 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005761 isolate->heap()->new_space()->
5762 template ShrinkStringAtAllocationBoundary<StringType>(
5763 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005764 return new_string;
5765}
5766
5767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005768RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005769 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005770 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005771 if (!str->IsFlat()) {
5772 MaybeObject* try_flatten = str->TryFlatten();
5773 Object* flat;
5774 if (!try_flatten->ToObject(&flat)) {
5775 return try_flatten;
5776 }
5777 str = String::cast(flat);
5778 ASSERT(str->IsFlat());
5779 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005780 String::FlatContent flat = str->GetFlatContent();
5781 ASSERT(flat.IsFlat());
5782 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005783 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005784 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005785 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005786 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005787 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005788 }
5789}
5790
5791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005792RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005793 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005794 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005795 if (!str->IsFlat()) {
5796 MaybeObject* try_flatten = str->TryFlatten();
5797 Object* flat;
5798 if (!try_flatten->ToObject(&flat)) {
5799 return try_flatten;
5800 }
5801 str = String::cast(flat);
5802 ASSERT(str->IsFlat());
5803 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005804 String::FlatContent flat = str->GetFlatContent();
5805 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005806 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005807 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005808 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005809 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005810 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005811 }
5812}
5813
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005814
5815template <typename Char, typename StringType>
5816static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5817 FixedArray* array,
5818 int worst_case_length) {
5819 int length = array->length();
5820
5821 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5822 worst_case_length);
5823 Object* new_object;
5824 if (!new_alloc->ToObject(&new_object)) {
5825 return new_alloc;
5826 }
5827 if (!isolate->heap()->new_space()->Contains(new_object)) {
5828 // Even if our string is small enough to fit in new space we still have to
5829 // handle it being allocated in old space as may happen in the third
5830 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5831 // CEntryStub::GenerateCore.
5832 return isolate->heap()->undefined_value();
5833 }
5834 AssertNoAllocation no_gc;
5835 StringType* new_string = StringType::cast(new_object);
5836 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5837
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005838 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005839 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005840 *(write_cursor++) = '[';
5841 for (int i = 0; i < length; i++) {
5842 if (i != 0) *(write_cursor++) = ',';
5843 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005844 String::FlatContent content = str->GetFlatContent();
5845 ASSERT(content.IsFlat());
5846 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005847 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5848 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005849 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005850 } else {
5851 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5852 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005853 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005854 }
5855 }
5856 *(write_cursor++) = ']';
5857
5858 int final_length = static_cast<int>(
5859 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005860 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005861 isolate->heap()->new_space()->
5862 template ShrinkStringAtAllocationBoundary<StringType>(
5863 new_string, final_length);
5864 return new_string;
5865}
5866
5867
5868RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5869 NoHandleAllocation ha;
5870 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005871 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005872
5873 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5874 FixedArray* elements = FixedArray::cast(array->elements());
5875 int n = elements->length();
5876 bool ascii = true;
5877 int total_length = 0;
5878
5879 for (int i = 0; i < n; i++) {
5880 Object* elt = elements->get(i);
5881 if (!elt->IsString()) return isolate->heap()->undefined_value();
5882 String* element = String::cast(elt);
5883 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5884 total_length += element->length();
5885 if (ascii && element->IsTwoByteRepresentation()) {
5886 ascii = false;
5887 }
5888 }
5889
5890 int worst_case_length =
5891 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5892 + total_length * kJsonQuoteWorstCaseBlowup;
5893
5894 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5895 return isolate->heap()->undefined_value();
5896 }
5897
5898 if (ascii) {
5899 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5900 elements,
5901 worst_case_length);
5902 } else {
5903 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5904 elements,
5905 worst_case_length);
5906 }
5907}
5908
5909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005910RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 NoHandleAllocation ha;
5912
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005913 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005914 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005916 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917
lrn@chromium.org25156de2010-04-06 13:10:27 +00005918 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005919 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921}
5922
5923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005924RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005926 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927
5928 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005929 double value = StringToDouble(isolate->unicode_cache(),
5930 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931
5932 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005933 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934}
5935
5936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005938MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005939 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005940 String* s,
5941 int length,
5942 int input_string_length,
5943 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005944 // We try this twice, once with the assumption that the result is no longer
5945 // than the input and, if that assumption breaks, again with the exact
5946 // length. This may not be pretty, but it is nicer than what was here before
5947 // and I hereby claim my vaffel-is.
5948 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949 // Allocate the resulting string.
5950 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005951 // NOTE: This assumes that the upper/lower case of an ASCII
5952 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953 // might break in the future if we implement more context and locale
5954 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005955 Object* o;
5956 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005957 ? isolate->heap()->AllocateRawAsciiString(length)
5958 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005959 if (!maybe_o->ToObject(&o)) return maybe_o;
5960 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961 String* result = String::cast(o);
5962 bool has_changed_character = false;
5963
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 // Convert all characters to upper case, assuming that they will fit
5965 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005966 Access<StringInputBuffer> buffer(
5967 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005969 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 // We can assume that the string is not empty
5971 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005972 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005973 bool has_next = buffer->has_more();
5974 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 int char_length = mapping->get(current, next, chars);
5976 if (char_length == 0) {
5977 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005978 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 i++;
5980 } else if (char_length == 1) {
5981 // Common case: converting the letter resulted in one character.
5982 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005983 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 has_changed_character = true;
5985 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005986 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 // We've assumed that the result would be as long as the
5988 // input but here is a character that converts to several
5989 // characters. No matter, we calculate the exact length
5990 // of the result and try the whole thing again.
5991 //
5992 // Note that this leaves room for optimization. We could just
5993 // memcpy what we already have to the result string. Also,
5994 // the result string is the last object allocated we could
5995 // "realloc" it and probably, in the vast majority of cases,
5996 // extend the existing string to be able to hold the full
5997 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005998 int next_length = 0;
5999 if (has_next) {
6000 next_length = mapping->get(next, 0, chars);
6001 if (next_length == 0) next_length = 1;
6002 }
6003 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 while (buffer->has_more()) {
6005 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006006 // NOTE: we use 0 as the next character here because, while
6007 // the next character may affect what a character converts to,
6008 // it does not in any case affect the length of what it convert
6009 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006010 int char_length = mapping->get(current, 0, chars);
6011 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006012 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006013 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006014 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006015 return Failure::OutOfMemoryException();
6016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006018 // Try again with the real length.
6019 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 } else {
6021 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006022 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 i++;
6024 }
6025 has_changed_character = true;
6026 }
6027 current = next;
6028 }
6029 if (has_changed_character) {
6030 return result;
6031 } else {
6032 // If we didn't actually change anything in doing the conversion
6033 // we simple return the result and let the converted string
6034 // become garbage; there is no reason to keep two identical strings
6035 // alive.
6036 return s;
6037 }
6038}
6039
6040
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006041namespace {
6042
lrn@chromium.org303ada72010-10-27 09:33:13 +00006043static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6044
6045
6046// Given a word and two range boundaries returns a word with high bit
6047// set in every byte iff the corresponding input byte was strictly in
6048// the range (m, n). All the other bits in the result are cleared.
6049// This function is only useful when it can be inlined and the
6050// boundaries are statically known.
6051// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006052// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006053static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006054 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006055 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6056 // Use strict inequalities since in edge cases the function could be
6057 // further simplified.
6058 ASSERT(0 < m && m < n && n < 0x7F);
6059 // Has high bit set in every w byte less than n.
6060 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6061 // Has high bit set in every w byte greater than m.
6062 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6063 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6064}
6065
6066
6067enum AsciiCaseConversion {
6068 ASCII_TO_LOWER,
6069 ASCII_TO_UPPER
6070};
6071
6072
6073template <AsciiCaseConversion dir>
6074struct FastAsciiConverter {
6075 static bool Convert(char* dst, char* src, int length) {
6076#ifdef DEBUG
6077 char* saved_dst = dst;
6078 char* saved_src = src;
6079#endif
6080 // We rely on the distance between upper and lower case letters
6081 // being a known power of 2.
6082 ASSERT('a' - 'A' == (1 << 5));
6083 // Boundaries for the range of input characters than require conversion.
6084 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6085 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6086 bool changed = false;
6087 char* const limit = src + length;
6088#ifdef V8_HOST_CAN_READ_UNALIGNED
6089 // Process the prefix of the input that requires no conversion one
6090 // (machine) word at a time.
6091 while (src <= limit - sizeof(uintptr_t)) {
6092 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6093 if (AsciiRangeMask(w, lo, hi) != 0) {
6094 changed = true;
6095 break;
6096 }
6097 *reinterpret_cast<uintptr_t*>(dst) = w;
6098 src += sizeof(uintptr_t);
6099 dst += sizeof(uintptr_t);
6100 }
6101 // Process the remainder of the input performing conversion when
6102 // required one word at a time.
6103 while (src <= limit - sizeof(uintptr_t)) {
6104 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6105 uintptr_t m = AsciiRangeMask(w, lo, hi);
6106 // The mask has high (7th) bit set in every byte that needs
6107 // conversion and we know that the distance between cases is
6108 // 1 << 5.
6109 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6110 src += sizeof(uintptr_t);
6111 dst += sizeof(uintptr_t);
6112 }
6113#endif
6114 // Process the last few bytes of the input (or the whole input if
6115 // unaligned access is not supported).
6116 while (src < limit) {
6117 char c = *src;
6118 if (lo < c && c < hi) {
6119 c ^= (1 << 5);
6120 changed = true;
6121 }
6122 *dst = c;
6123 ++src;
6124 ++dst;
6125 }
6126#ifdef DEBUG
6127 CheckConvert(saved_dst, saved_src, length, changed);
6128#endif
6129 return changed;
6130 }
6131
6132#ifdef DEBUG
6133 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6134 bool expected_changed = false;
6135 for (int i = 0; i < length; i++) {
6136 if (dst[i] == src[i]) continue;
6137 expected_changed = true;
6138 if (dir == ASCII_TO_LOWER) {
6139 ASSERT('A' <= src[i] && src[i] <= 'Z');
6140 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6141 } else {
6142 ASSERT(dir == ASCII_TO_UPPER);
6143 ASSERT('a' <= src[i] && src[i] <= 'z');
6144 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6145 }
6146 }
6147 ASSERT(expected_changed == changed);
6148 }
6149#endif
6150};
6151
6152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006153struct ToLowerTraits {
6154 typedef unibrow::ToLowercase UnibrowConverter;
6155
lrn@chromium.org303ada72010-10-27 09:33:13 +00006156 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006157};
6158
6159
6160struct ToUpperTraits {
6161 typedef unibrow::ToUppercase UnibrowConverter;
6162
lrn@chromium.org303ada72010-10-27 09:33:13 +00006163 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164};
6165
6166} // namespace
6167
6168
6169template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006170MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006172 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006173 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006174 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006175 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006176 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006177
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006178 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006179 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006180 if (length == 0) return s;
6181
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006182 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006183 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006184 // NOTE: This assumes that the upper/lower case of an ASCII
6185 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006186 // might break in the future if we implement more context and locale
6187 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006188 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006189 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006190 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006191 if (!maybe_o->ToObject(&o)) return maybe_o;
6192 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006193 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006194 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006195 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196 return has_changed_character ? result : s;
6197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006198
lrn@chromium.org303ada72010-10-27 09:33:13 +00006199 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006200 { MaybeObject* maybe_answer =
6201 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006202 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6203 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006204 if (answer->IsSmi()) {
6205 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006206 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 ConvertCaseHelper(isolate,
6208 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6210 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006211 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006212 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006213}
6214
6215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006216RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006217 return ConvertCase<ToLowerTraits>(
6218 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219}
6220
6221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006222RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006223 return ConvertCase<ToUpperTraits>(
6224 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006225}
6226
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006227
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006228static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006229 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006230}
6231
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006233RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006234 NoHandleAllocation ha;
6235 ASSERT(args.length() == 3);
6236
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006237 CONVERT_ARG_CHECKED(String, s, 0);
6238 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6239 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006241 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006242 int length = s->length();
6243
6244 int left = 0;
6245 if (trimLeft) {
6246 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6247 left++;
6248 }
6249 }
6250
6251 int right = length;
6252 if (trimRight) {
6253 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6254 right--;
6255 }
6256 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006257 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006258}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006259
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006261RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006262 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006263 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006264 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6265 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006266 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6267
6268 int subject_length = subject->length();
6269 int pattern_length = pattern->length();
6270 RUNTIME_ASSERT(pattern_length > 0);
6271
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006272 if (limit == 0xffffffffu) {
6273 Handle<Object> cached_answer(StringSplitCache::Lookup(
6274 isolate->heap()->string_split_cache(),
6275 *subject,
6276 *pattern));
6277 if (*cached_answer != Smi::FromInt(0)) {
6278 Handle<JSArray> result =
6279 isolate->factory()->NewJSArrayWithElements(
6280 Handle<FixedArray>::cast(cached_answer));
6281 return *result;
6282 }
6283 }
6284
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006285 // The limit can be very large (0xffffffffu), but since the pattern
6286 // isn't empty, we can never create more parts than ~half the length
6287 // of the subject.
6288
6289 if (!subject->IsFlat()) FlattenString(subject);
6290
6291 static const int kMaxInitialListCapacity = 16;
6292
danno@chromium.org40cb8782011-05-25 07:58:50 +00006293 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006294
6295 // Find (up to limit) indices of separator and end-of-string in subject
6296 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6297 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006298 if (!pattern->IsFlat()) FlattenString(pattern);
6299
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006300 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006301
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006302 if (static_cast<uint32_t>(indices.length()) < limit) {
6303 indices.Add(subject_length);
6304 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006306 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006307
6308 // Create JSArray of substrings separated by separator.
6309 int part_count = indices.length();
6310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006312 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006313 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006314 result->set_length(Smi::FromInt(part_count));
6315
6316 ASSERT(result->HasFastElements());
6317
6318 if (part_count == 1 && indices.at(0) == subject_length) {
6319 FixedArray::cast(result->elements())->set(0, *subject);
6320 return *result;
6321 }
6322
6323 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6324 int part_start = 0;
6325 for (int i = 0; i < part_count; i++) {
6326 HandleScope local_loop_handle;
6327 int part_end = indices.at(i);
6328 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006329 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006330 elements->set(i, *substring);
6331 part_start = part_end + pattern_length;
6332 }
6333
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006334 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006335 if (result->HasFastElements()) {
6336 StringSplitCache::Enter(isolate->heap(),
6337 isolate->heap()->string_split_cache(),
6338 *subject,
6339 *pattern,
6340 *elements);
6341 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006342 }
6343
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006344 return *result;
6345}
6346
6347
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006348// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349// one-char strings in the cache. Gives up on the first char that is
6350// not in the cache and fills the remainder with smi zeros. Returns
6351// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006352static int CopyCachedAsciiCharsToArray(Heap* heap,
6353 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006354 FixedArray* elements,
6355 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006356 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006357 FixedArray* ascii_cache = heap->single_character_string_cache();
6358 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006359 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006360 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006361 for (i = 0; i < length; ++i) {
6362 Object* value = ascii_cache->get(chars[i]);
6363 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006364 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006365 }
6366 if (i < length) {
6367 ASSERT(Smi::FromInt(0) == 0);
6368 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6369 }
6370#ifdef DEBUG
6371 for (int j = 0; j < length; ++j) {
6372 Object* element = elements->get(j);
6373 ASSERT(element == Smi::FromInt(0) ||
6374 (element->IsString() && String::cast(element)->LooksValid()));
6375 }
6376#endif
6377 return i;
6378}
6379
6380
6381// Converts a String to JSArray.
6382// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006383RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006384 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006385 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006386 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006387 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006388
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006389 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006390 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391
6392 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006393 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006394 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006395 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006396 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006397 { MaybeObject* maybe_obj =
6398 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006399 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006401 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006402 String::FlatContent content = s->GetFlatContent();
6403 if (content.IsAscii()) {
6404 Vector<const char> chars = content.ToAsciiVector();
6405 // Note, this will initialize all elements (not only the prefix)
6406 // to prevent GC from seeing partially initialized array.
6407 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6408 chars.start(),
6409 *elements,
6410 length);
6411 } else {
6412 MemsetPointer(elements->data_start(),
6413 isolate->heap()->undefined_value(),
6414 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006415 }
6416 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006417 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006418 }
6419 for (int i = position; i < length; ++i) {
6420 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6421 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006422 }
6423
6424#ifdef DEBUG
6425 for (int i = 0; i < length; ++i) {
6426 ASSERT(String::cast(elements->get(i))->length() == 1);
6427 }
6428#endif
6429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006431}
6432
6433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006434RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006435 NoHandleAllocation ha;
6436 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006437 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006438 return value->ToObject();
6439}
6440
6441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006442bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006443 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006445 return char_length == 0;
6446}
6447
6448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006449RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006450 NoHandleAllocation ha;
6451 ASSERT(args.length() == 1);
6452
6453 Object* number = args[0];
6454 RUNTIME_ASSERT(number->IsNumber());
6455
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457}
6458
6459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006460RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006461 NoHandleAllocation ha;
6462 ASSERT(args.length() == 1);
6463
6464 Object* number = args[0];
6465 RUNTIME_ASSERT(number->IsNumber());
6466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006468}
6469
6470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006471RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006472 NoHandleAllocation ha;
6473 ASSERT(args.length() == 1);
6474
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006475 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006476
6477 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6478 if (number > 0 && number <= Smi::kMaxValue) {
6479 return Smi::FromInt(static_cast<int>(number));
6480 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006481 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482}
6483
6484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006485RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006486 NoHandleAllocation ha;
6487 ASSERT(args.length() == 1);
6488
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006489 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006490
6491 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6492 if (number > 0 && number <= Smi::kMaxValue) {
6493 return Smi::FromInt(static_cast<int>(number));
6494 }
6495
6496 double double_value = DoubleToInteger(number);
6497 // Map both -0 and +0 to +0.
6498 if (double_value == 0) double_value = 0;
6499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006500 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006501}
6502
6503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006504RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 NoHandleAllocation ha;
6506 ASSERT(args.length() == 1);
6507
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006508 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510}
6511
6512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006513RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006514 NoHandleAllocation ha;
6515 ASSERT(args.length() == 1);
6516
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006517 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006518
6519 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6520 if (number > 0 && number <= Smi::kMaxValue) {
6521 return Smi::FromInt(static_cast<int>(number));
6522 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006523 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006524}
6525
6526
ager@chromium.org870a0b62008-11-04 11:43:05 +00006527// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6528// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006529RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006530 NoHandleAllocation ha;
6531 ASSERT(args.length() == 1);
6532
6533 Object* obj = args[0];
6534 if (obj->IsSmi()) {
6535 return obj;
6536 }
6537 if (obj->IsHeapNumber()) {
6538 double value = HeapNumber::cast(obj)->value();
6539 int int_value = FastD2I(value);
6540 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6541 return Smi::FromInt(int_value);
6542 }
6543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006544 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006545}
6546
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006548RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006549 NoHandleAllocation ha;
6550 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006552}
6553
6554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006555RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006556 NoHandleAllocation ha;
6557 ASSERT(args.length() == 2);
6558
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006559 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6560 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562}
6563
6564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006565RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 NoHandleAllocation ha;
6567 ASSERT(args.length() == 2);
6568
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006569 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6570 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006571 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572}
6573
6574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006575RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 NoHandleAllocation ha;
6577 ASSERT(args.length() == 2);
6578
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006579 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6580 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582}
6583
6584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586 NoHandleAllocation ha;
6587 ASSERT(args.length() == 1);
6588
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006589 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006590 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006591}
6592
6593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006594RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006595 NoHandleAllocation ha;
6596 ASSERT(args.length() == 0);
6597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006598 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006599}
6600
6601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006602RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 NoHandleAllocation ha;
6604 ASSERT(args.length() == 2);
6605
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006606 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6607 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609}
6610
6611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006612RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613 NoHandleAllocation ha;
6614 ASSERT(args.length() == 2);
6615
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006616 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6617 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618
ager@chromium.org3811b432009-10-28 14:53:37 +00006619 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006620 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006621 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622}
6623
6624
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006625RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626 NoHandleAllocation ha;
6627 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006628 CONVERT_ARG_CHECKED(String, str1, 0);
6629 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006630 isolate->counters()->string_add_runtime()->Increment();
6631 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632}
6633
6634
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006635template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006636static inline void StringBuilderConcatHelper(String* special,
6637 sinkchar* sink,
6638 FixedArray* fixed_array,
6639 int array_length) {
6640 int position = 0;
6641 for (int i = 0; i < array_length; i++) {
6642 Object* element = fixed_array->get(i);
6643 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006644 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006645 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006646 int pos;
6647 int len;
6648 if (encoded_slice > 0) {
6649 // Position and length encoded in one smi.
6650 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6651 len = StringBuilderSubstringLength::decode(encoded_slice);
6652 } else {
6653 // Position and length encoded in two smis.
6654 Object* obj = fixed_array->get(++i);
6655 ASSERT(obj->IsSmi());
6656 pos = Smi::cast(obj)->value();
6657 len = -encoded_slice;
6658 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006659 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006660 sink + position,
6661 pos,
6662 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006663 position += len;
6664 } else {
6665 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006666 int element_length = string->length();
6667 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006668 position += element_length;
6669 }
6670 }
6671}
6672
6673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006674RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006676 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006677 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006678 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006680 return Failure::OutOfMemoryException();
6681 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006682 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006683 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006684
6685 // This assumption is used by the slice encoding in one or two smis.
6686 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6687
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006688 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006689 if (maybe_result->IsFailure()) return maybe_result;
6690
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006691 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006693 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694 }
6695 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006696 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006698 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699
6700 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006701 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702 } else if (array_length == 1) {
6703 Object* first = fixed_array->get(0);
6704 if (first->IsString()) return first;
6705 }
6706
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006707 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006708 int position = 0;
6709 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006710 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711 Object* elt = fixed_array->get(i);
6712 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006713 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006714 int smi_value = Smi::cast(elt)->value();
6715 int pos;
6716 int len;
6717 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006718 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006719 pos = StringBuilderSubstringPosition::decode(smi_value);
6720 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006721 } else {
6722 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006723 len = -smi_value;
6724 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006725 i++;
6726 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006727 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006728 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006729 Object* next_smi = fixed_array->get(i);
6730 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006731 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006732 }
6733 pos = Smi::cast(next_smi)->value();
6734 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006735 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006736 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006738 ASSERT(pos >= 0);
6739 ASSERT(len >= 0);
6740 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006741 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006742 }
6743 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 } else if (elt->IsString()) {
6745 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006746 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006747 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006748 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006750 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006752 ASSERT(!elt->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006753 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006755 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006756 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006757 return Failure::OutOfMemoryException();
6758 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006759 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760 }
6761
6762 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006764
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006766 { MaybeObject* maybe_object =
6767 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006768 if (!maybe_object->ToObject(&object)) return maybe_object;
6769 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006770 SeqAsciiString* answer = SeqAsciiString::cast(object);
6771 StringBuilderConcatHelper(special,
6772 answer->GetChars(),
6773 fixed_array,
6774 array_length);
6775 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006777 { MaybeObject* maybe_object =
6778 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006779 if (!maybe_object->ToObject(&object)) return maybe_object;
6780 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006781 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6782 StringBuilderConcatHelper(special,
6783 answer->GetChars(),
6784 fixed_array,
6785 array_length);
6786 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006788}
6789
6790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006791RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006792 NoHandleAllocation ha;
6793 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006794 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006795 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006797 return Failure::OutOfMemoryException();
6798 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006799 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006800 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006801
6802 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006803 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006804 }
6805 FixedArray* fixed_array = FixedArray::cast(array->elements());
6806 if (fixed_array->length() < array_length) {
6807 array_length = fixed_array->length();
6808 }
6809
6810 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006811 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006812 } else if (array_length == 1) {
6813 Object* first = fixed_array->get(0);
6814 if (first->IsString()) return first;
6815 }
6816
6817 int separator_length = separator->length();
6818 int max_nof_separators =
6819 (String::kMaxLength + separator_length - 1) / separator_length;
6820 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006821 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006822 return Failure::OutOfMemoryException();
6823 }
6824 int length = (array_length - 1) * separator_length;
6825 for (int i = 0; i < array_length; i++) {
6826 Object* element_obj = fixed_array->get(i);
6827 if (!element_obj->IsString()) {
6828 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006829 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006830 }
6831 String* element = String::cast(element_obj);
6832 int increment = element->length();
6833 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006834 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006835 return Failure::OutOfMemoryException();
6836 }
6837 length += increment;
6838 }
6839
6840 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006841 { MaybeObject* maybe_object =
6842 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006843 if (!maybe_object->ToObject(&object)) return maybe_object;
6844 }
6845 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6846
6847 uc16* sink = answer->GetChars();
6848#ifdef DEBUG
6849 uc16* end = sink + length;
6850#endif
6851
6852 String* first = String::cast(fixed_array->get(0));
6853 int first_length = first->length();
6854 String::WriteToFlat(first, sink, 0, first_length);
6855 sink += first_length;
6856
6857 for (int i = 1; i < array_length; i++) {
6858 ASSERT(sink + separator_length <= end);
6859 String::WriteToFlat(separator, sink, 0, separator_length);
6860 sink += separator_length;
6861
6862 String* element = String::cast(fixed_array->get(i));
6863 int element_length = element->length();
6864 ASSERT(sink + element_length <= end);
6865 String::WriteToFlat(element, sink, 0, element_length);
6866 sink += element_length;
6867 }
6868 ASSERT(sink == end);
6869
6870 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6871 return answer;
6872}
6873
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006874template <typename Char>
6875static void JoinSparseArrayWithSeparator(FixedArray* elements,
6876 int elements_length,
6877 uint32_t array_length,
6878 String* separator,
6879 Vector<Char> buffer) {
6880 int previous_separator_position = 0;
6881 int separator_length = separator->length();
6882 int cursor = 0;
6883 for (int i = 0; i < elements_length; i += 2) {
6884 int position = NumberToInt32(elements->get(i));
6885 String* string = String::cast(elements->get(i + 1));
6886 int string_length = string->length();
6887 if (string->length() > 0) {
6888 while (previous_separator_position < position) {
6889 String::WriteToFlat<Char>(separator, &buffer[cursor],
6890 0, separator_length);
6891 cursor += separator_length;
6892 previous_separator_position++;
6893 }
6894 String::WriteToFlat<Char>(string, &buffer[cursor],
6895 0, string_length);
6896 cursor += string->length();
6897 }
6898 }
6899 if (separator_length > 0) {
6900 // Array length must be representable as a signed 32-bit number,
6901 // otherwise the total string length would have been too large.
6902 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6903 int last_array_index = static_cast<int>(array_length - 1);
6904 while (previous_separator_position < last_array_index) {
6905 String::WriteToFlat<Char>(separator, &buffer[cursor],
6906 0, separator_length);
6907 cursor += separator_length;
6908 previous_separator_position++;
6909 }
6910 }
6911 ASSERT(cursor <= buffer.length());
6912}
6913
6914
6915RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6916 NoHandleAllocation ha;
6917 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006918 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006919 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6920 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006921 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006922 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006923 // elements_array is fast-mode JSarray of alternating positions
6924 // (increasing order) and strings.
6925 // array_length is length of original array (used to add separators);
6926 // separator is string to put between elements. Assumed to be non-empty.
6927
6928 // Find total length of join result.
6929 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006930 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006931 int max_string_length;
6932 if (is_ascii) {
6933 max_string_length = SeqAsciiString::kMaxLength;
6934 } else {
6935 max_string_length = SeqTwoByteString::kMaxLength;
6936 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006937 bool overflow = false;
6938 CONVERT_NUMBER_CHECKED(int, elements_length,
6939 Int32, elements_array->length());
6940 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6941 FixedArray* elements = FixedArray::cast(elements_array->elements());
6942 for (int i = 0; i < elements_length; i += 2) {
6943 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006944 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6945 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006946 int length = string->length();
6947 if (is_ascii && !string->IsAsciiRepresentation()) {
6948 is_ascii = false;
6949 max_string_length = SeqTwoByteString::kMaxLength;
6950 }
6951 if (length > max_string_length ||
6952 max_string_length - length < string_length) {
6953 overflow = true;
6954 break;
6955 }
6956 string_length += length;
6957 }
6958 int separator_length = separator->length();
6959 if (!overflow && separator_length > 0) {
6960 if (array_length <= 0x7fffffffu) {
6961 int separator_count = static_cast<int>(array_length) - 1;
6962 int remaining_length = max_string_length - string_length;
6963 if ((remaining_length / separator_length) >= separator_count) {
6964 string_length += separator_length * (array_length - 1);
6965 } else {
6966 // Not room for the separators within the maximal string length.
6967 overflow = true;
6968 }
6969 } else {
6970 // Nonempty separator and at least 2^31-1 separators necessary
6971 // means that the string is too large to create.
6972 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6973 overflow = true;
6974 }
6975 }
6976 if (overflow) {
6977 // Throw OutOfMemory exception for creating too large a string.
6978 V8::FatalProcessOutOfMemory("Array join result too large.");
6979 }
6980
6981 if (is_ascii) {
6982 MaybeObject* result_allocation =
6983 isolate->heap()->AllocateRawAsciiString(string_length);
6984 if (result_allocation->IsFailure()) return result_allocation;
6985 SeqAsciiString* result_string =
6986 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6987 JoinSparseArrayWithSeparator<char>(elements,
6988 elements_length,
6989 array_length,
6990 separator,
6991 Vector<char>(result_string->GetChars(),
6992 string_length));
6993 return result_string;
6994 } else {
6995 MaybeObject* result_allocation =
6996 isolate->heap()->AllocateRawTwoByteString(string_length);
6997 if (result_allocation->IsFailure()) return result_allocation;
6998 SeqTwoByteString* result_string =
6999 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7000 JoinSparseArrayWithSeparator<uc16>(elements,
7001 elements_length,
7002 array_length,
7003 separator,
7004 Vector<uc16>(result_string->GetChars(),
7005 string_length));
7006 return result_string;
7007 }
7008}
7009
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007011RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007012 NoHandleAllocation ha;
7013 ASSERT(args.length() == 2);
7014
7015 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7016 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007017 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007018}
7019
7020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007021RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 NoHandleAllocation ha;
7023 ASSERT(args.length() == 2);
7024
7025 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7026 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007027 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028}
7029
7030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032 NoHandleAllocation ha;
7033 ASSERT(args.length() == 2);
7034
7035 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7036 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038}
7039
7040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042 NoHandleAllocation ha;
7043 ASSERT(args.length() == 1);
7044
7045 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007046 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047}
7048
7049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007050RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051 NoHandleAllocation ha;
7052 ASSERT(args.length() == 2);
7053
7054 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7055 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007056 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057}
7058
7059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007060RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 NoHandleAllocation ha;
7062 ASSERT(args.length() == 2);
7063
7064 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7065 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007066 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067}
7068
7069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007084 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7085 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007086 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7087 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7088 if (x == y) return Smi::FromInt(EQUAL);
7089 Object* result;
7090 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7091 result = Smi::FromInt(EQUAL);
7092 } else {
7093 result = Smi::FromInt(NOT_EQUAL);
7094 }
7095 return result;
7096}
7097
7098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 NoHandleAllocation ha;
7101 ASSERT(args.length() == 2);
7102
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007103 CONVERT_ARG_CHECKED(String, x, 0);
7104 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007105
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007106 bool not_equal = !x->Equals(y);
7107 // This is slightly convoluted because the value that signifies
7108 // equality is 0 and inequality is 1 so we have to negate the result
7109 // from String::Equals.
7110 ASSERT(not_equal == 0 || not_equal == 1);
7111 STATIC_CHECK(EQUAL == 0);
7112 STATIC_CHECK(NOT_EQUAL == 1);
7113 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114}
7115
7116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007117RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007118 NoHandleAllocation ha;
7119 ASSERT(args.length() == 3);
7120
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007121 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7122 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007123 if (isnan(x) || isnan(y)) return args[2];
7124 if (x == y) return Smi::FromInt(EQUAL);
7125 if (isless(x, y)) return Smi::FromInt(LESS);
7126 return Smi::FromInt(GREATER);
7127}
7128
7129
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007130// Compare two Smis as if they were converted to strings and then
7131// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007132RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007133 NoHandleAllocation ha;
7134 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007135 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7136 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007137
7138 // If the integers are equal so are the string representations.
7139 if (x_value == y_value) return Smi::FromInt(EQUAL);
7140
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007141 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007142 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007143 if (x_value == 0 || y_value == 0)
7144 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007145
ager@chromium.org32912102009-01-16 10:38:43 +00007146 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007147 // smallest because the char code of '-' is less than the char code
7148 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007149
7150 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7151 // architectures using 32-bit Smis.
7152 uint32_t x_scaled = x_value;
7153 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007154 if (x_value < 0 || y_value < 0) {
7155 if (y_value >= 0) return Smi::FromInt(LESS);
7156 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007157 x_scaled = -x_value;
7158 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007159 }
7160
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007161 static const uint32_t kPowersOf10[] = {
7162 1, 10, 100, 1000, 10*1000, 100*1000,
7163 1000*1000, 10*1000*1000, 100*1000*1000,
7164 1000*1000*1000
7165 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007166
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007167 // If the integers have the same number of decimal digits they can be
7168 // compared directly as the numeric order is the same as the
7169 // lexicographic order. If one integer has fewer digits, it is scaled
7170 // by some power of 10 to have the same number of digits as the longer
7171 // integer. If the scaled integers are equal it means the shorter
7172 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007173
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007174 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7175 int x_log2 = IntegerLog2(x_scaled);
7176 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7177 x_log10 -= x_scaled < kPowersOf10[x_log10];
7178
7179 int y_log2 = IntegerLog2(y_scaled);
7180 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7181 y_log10 -= y_scaled < kPowersOf10[y_log10];
7182
7183 int tie = EQUAL;
7184
7185 if (x_log10 < y_log10) {
7186 // X has fewer digits. We would like to simply scale up X but that
7187 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7188 // be scaled up to 9_000_000_000. So we scale up by the next
7189 // smallest power and scale down Y to drop one digit. It is OK to
7190 // drop one digit from the longer integer since the final digit is
7191 // past the length of the shorter integer.
7192 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7193 y_scaled /= 10;
7194 tie = LESS;
7195 } else if (y_log10 < x_log10) {
7196 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7197 x_scaled /= 10;
7198 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007199 }
7200
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007201 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7202 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7203 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007204}
7205
7206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007207static Object* StringInputBufferCompare(RuntimeState* state,
7208 String* x,
7209 String* y) {
7210 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7211 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007212 bufx.Reset(x);
7213 bufy.Reset(y);
7214 while (bufx.has_more() && bufy.has_more()) {
7215 int d = bufx.GetNext() - bufy.GetNext();
7216 if (d < 0) return Smi::FromInt(LESS);
7217 else if (d > 0) return Smi::FromInt(GREATER);
7218 }
7219
7220 // x is (non-trivial) prefix of y:
7221 if (bufy.has_more()) return Smi::FromInt(LESS);
7222 // y is prefix of x:
7223 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7224}
7225
7226
7227static Object* FlatStringCompare(String* x, String* y) {
7228 ASSERT(x->IsFlat());
7229 ASSERT(y->IsFlat());
7230 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7231 int prefix_length = x->length();
7232 if (y->length() < prefix_length) {
7233 prefix_length = y->length();
7234 equal_prefix_result = Smi::FromInt(GREATER);
7235 } else if (y->length() > prefix_length) {
7236 equal_prefix_result = Smi::FromInt(LESS);
7237 }
7238 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007239 String::FlatContent x_content = x->GetFlatContent();
7240 String::FlatContent y_content = y->GetFlatContent();
7241 if (x_content.IsAscii()) {
7242 Vector<const char> x_chars = x_content.ToAsciiVector();
7243 if (y_content.IsAscii()) {
7244 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007245 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007246 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007247 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007248 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7249 }
7250 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007251 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7252 if (y_content.IsAscii()) {
7253 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007254 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7255 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007256 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007257 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7258 }
7259 }
7260 Object* result;
7261 if (r == 0) {
7262 result = equal_prefix_result;
7263 } else {
7264 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7265 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007266 ASSERT(result ==
7267 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007268 return result;
7269}
7270
7271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007272RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007273 NoHandleAllocation ha;
7274 ASSERT(args.length() == 2);
7275
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007276 CONVERT_ARG_CHECKED(String, x, 0);
7277 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007279 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281 // A few fast case tests before we flatten.
7282 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007283 if (y->length() == 0) {
7284 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007286 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287 return Smi::FromInt(LESS);
7288 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007289
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007290 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007291 if (d < 0) return Smi::FromInt(LESS);
7292 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007293
lrn@chromium.org303ada72010-10-27 09:33:13 +00007294 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007295 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007296 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7297 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007298 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007299 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7300 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007302 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007303 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304}
7305
7306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007307RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308 NoHandleAllocation ha;
7309 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007310 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007312 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314}
7315
7316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007317RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318 NoHandleAllocation ha;
7319 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007322 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324}
7325
7326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007327RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007328 NoHandleAllocation ha;
7329 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007330 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007332 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334}
7335
7336
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007337static const double kPiDividedBy4 = 0.78539816339744830962;
7338
7339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007340RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341 NoHandleAllocation ha;
7342 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007345 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7346 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347 double result;
7348 if (isinf(x) && isinf(y)) {
7349 // Make sure that the result in case of two infinite arguments
7350 // is a multiple of Pi / 4. The sign of the result is determined
7351 // by the first argument (x) and the sign of the second argument
7352 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353 int multiplier = (x < 0) ? -1 : 1;
7354 if (y < 0) multiplier *= 3;
7355 result = multiplier * kPiDividedBy4;
7356 } else {
7357 result = atan2(x, y);
7358 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360}
7361
7362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007363RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364 NoHandleAllocation ha;
7365 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007368 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370}
7371
7372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007373RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380}
7381
7382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007383RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 NoHandleAllocation ha;
7385 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007388 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390}
7391
7392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007393RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394 NoHandleAllocation ha;
7395 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007398 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400}
7401
7402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410}
7411
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007412// Slow version of Math.pow. We check for fast paths for special cases.
7413// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007414RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415 NoHandleAllocation ha;
7416 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007417 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007418
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007419 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007420
7421 // If the second argument is a smi, it is much faster to call the
7422 // custom powi() function than the generic pow().
7423 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007424 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007425 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007426 }
7427
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007428 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007429 int y_int = static_cast<int>(y);
7430 double result;
7431 if (y == y_int) {
7432 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7433 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007434 result = (isinf(x)) ? V8_INFINITY
7435 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007436 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007437 result = (isinf(x)) ? 0
7438 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007439 } else {
7440 result = power_double_double(x, y);
7441 }
7442 if (isnan(result)) return isolate->heap()->nan_value();
7443 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007444}
7445
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007446// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007447// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007448RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007449 NoHandleAllocation ha;
7450 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007451 isolate->counters()->math_pow()->Increment();
7452
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007453 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7454 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007455 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007456 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007457 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007458 double result = power_double_double(x, y);
7459 if (isnan(result)) return isolate->heap()->nan_value();
7460 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007461 }
7462}
7463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007465RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007466 NoHandleAllocation ha;
7467 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007468 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007469
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007470 if (!args[0]->IsHeapNumber()) {
7471 // Must be smi. Return the argument unchanged for all the other types
7472 // to make fuzz-natives test happy.
7473 return args[0];
7474 }
7475
7476 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7477
7478 double value = number->value();
7479 int exponent = number->get_exponent();
7480 int sign = number->get_sign();
7481
danno@chromium.org160a7b02011-04-18 15:51:38 +00007482 if (exponent < -1) {
7483 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7484 if (sign) return isolate->heap()->minus_zero_value();
7485 return Smi::FromInt(0);
7486 }
7487
7488 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7489 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007490 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007491 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007492 return Smi::FromInt(static_cast<int>(value + 0.5));
7493 }
7494
7495 // If the magnitude is big enough, there's no place for fraction part. If we
7496 // try to add 0.5 to this number, 1.0 will be added instead.
7497 if (exponent >= 52) {
7498 return number;
7499 }
7500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007501 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007502
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007503 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007504 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505}
7506
7507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007508RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007509 NoHandleAllocation ha;
7510 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007513 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515}
7516
7517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007518RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519 NoHandleAllocation ha;
7520 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007523 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007524 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525}
7526
7527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007528RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007529 NoHandleAllocation ha;
7530 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007533 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007534 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007535}
7536
7537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007538RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007539 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007540 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007541
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007542 CONVERT_SMI_ARG_CHECKED(year, 0);
7543 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007544
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007545 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007546}
7547
7548
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007549RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7550 HandleScope scope(isolate);
7551 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007552
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007553 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7554 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7555 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007556
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007557 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007558
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007559 Object* value = NULL;
7560 bool is_value_nan = false;
7561 if (isnan(time)) {
7562 value = isolate->heap()->nan_value();
7563 is_value_nan = true;
7564 } else if (!is_utc &&
7565 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7566 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7567 value = isolate->heap()->nan_value();
7568 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007569 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007570 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7571 if (time < -DateCache::kMaxTimeInMs ||
7572 time > DateCache::kMaxTimeInMs) {
7573 value = isolate->heap()->nan_value();
7574 is_value_nan = true;
7575 } else {
7576 MaybeObject* maybe_result =
7577 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7578 if (!maybe_result->ToObject(&value)) return maybe_result;
7579 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007580 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007581 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007582 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007583}
7584
7585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007586RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007587 HandleScope scope(isolate);
7588 ASSERT(args.length() == 3);
7589
7590 Handle<JSFunction> callee = args.at<JSFunction>(0);
7591 Object** parameters = reinterpret_cast<Object**>(args[1]);
7592 const int argument_count = Smi::cast(args[2])->value();
7593
7594 Handle<JSObject> result =
7595 isolate->factory()->NewArgumentsObject(callee, argument_count);
7596 // Allocate the elements if needed.
7597 int parameter_count = callee->shared()->formal_parameter_count();
7598 if (argument_count > 0) {
7599 if (parameter_count > 0) {
7600 int mapped_count = Min(argument_count, parameter_count);
7601 Handle<FixedArray> parameter_map =
7602 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7603 parameter_map->set_map(
7604 isolate->heap()->non_strict_arguments_elements_map());
7605
7606 Handle<Map> old_map(result->map());
7607 Handle<Map> new_map =
7608 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007609 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007610
7611 result->set_map(*new_map);
7612 result->set_elements(*parameter_map);
7613
7614 // Store the context and the arguments array at the beginning of the
7615 // parameter map.
7616 Handle<Context> context(isolate->context());
7617 Handle<FixedArray> arguments =
7618 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7619 parameter_map->set(0, *context);
7620 parameter_map->set(1, *arguments);
7621
7622 // Loop over the actual parameters backwards.
7623 int index = argument_count - 1;
7624 while (index >= mapped_count) {
7625 // These go directly in the arguments array and have no
7626 // corresponding slot in the parameter map.
7627 arguments->set(index, *(parameters - index - 1));
7628 --index;
7629 }
7630
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007631 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007632 while (index >= 0) {
7633 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007634 Handle<String> name(scope_info->ParameterName(index));
7635 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007636 bool duplicate = false;
7637 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007638 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007639 duplicate = true;
7640 break;
7641 }
7642 }
7643
7644 if (duplicate) {
7645 // This goes directly in the arguments array with a hole in the
7646 // parameter map.
7647 arguments->set(index, *(parameters - index - 1));
7648 parameter_map->set_the_hole(index + 2);
7649 } else {
7650 // The context index goes in the parameter map with a hole in the
7651 // arguments array.
7652 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007653 for (int j = 0; j < context_local_count; ++j) {
7654 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007655 context_index = j;
7656 break;
7657 }
7658 }
7659 ASSERT(context_index >= 0);
7660 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007661 parameter_map->set(index + 2, Smi::FromInt(
7662 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007663 }
7664
7665 --index;
7666 }
7667 } else {
7668 // If there is no aliasing, the arguments object elements are not
7669 // special in any way.
7670 Handle<FixedArray> elements =
7671 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7672 result->set_elements(*elements);
7673 for (int i = 0; i < argument_count; ++i) {
7674 elements->set(i, *(parameters - i - 1));
7675 }
7676 }
7677 }
7678 return *result;
7679}
7680
7681
7682RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007683 NoHandleAllocation ha;
7684 ASSERT(args.length() == 3);
7685
7686 JSFunction* callee = JSFunction::cast(args[0]);
7687 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007688 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007689
lrn@chromium.org303ada72010-10-27 09:33:13 +00007690 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007691 { MaybeObject* maybe_result =
7692 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007693 if (!maybe_result->ToObject(&result)) return maybe_result;
7694 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007695 // Allocate the elements if needed.
7696 if (length > 0) {
7697 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007698 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007699 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007700 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7701 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007702
7703 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007704 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007705 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007706 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007707
7708 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007709 for (int i = 0; i < length; i++) {
7710 array->set(i, *--parameters, mode);
7711 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007712 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007713 }
7714 return result;
7715}
7716
7717
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007718RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007719 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007720 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007721 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7722 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7723 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007724
whesse@chromium.org7b260152011-06-20 15:33:18 +00007725 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007726 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007727 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007728 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007729 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7730 context,
7731 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007732 return *result;
7733}
7734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007735
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007736// Find the arguments of the JavaScript function invocation that called
7737// into C++ code. Collect these in a newly allocated array of handles (possibly
7738// prefixed by a number of empty handles).
7739static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7740 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007741 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007742 // Find frame containing arguments passed to the caller.
7743 JavaScriptFrameIterator it;
7744 JavaScriptFrame* frame = it.frame();
7745 List<JSFunction*> functions(2);
7746 frame->GetFunctions(&functions);
7747 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007748 int inlined_jsframe_index = functions.length() - 1;
7749 JSFunction* inlined_function = functions[inlined_jsframe_index];
7750 Vector<SlotRef> args_slots =
7751 SlotRef::ComputeSlotMappingForArguments(
7752 frame,
7753 inlined_jsframe_index,
7754 inlined_function->shared()->formal_parameter_count());
7755
7756 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007757
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007758 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007759 SmartArrayPointer<Handle<Object> > param_data(
7760 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007761 for (int i = 0; i < args_count; i++) {
7762 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007763 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007764 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007765
7766 args_slots.Dispose();
7767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007768 return param_data;
7769 } else {
7770 it.AdvanceToArgumentsFrame();
7771 frame = it.frame();
7772 int args_count = frame->ComputeParametersCount();
7773
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007774 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007775 SmartArrayPointer<Handle<Object> > param_data(
7776 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007777 for (int i = 0; i < args_count; i++) {
7778 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007779 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007780 }
7781 return param_data;
7782 }
7783}
7784
7785
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007786RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7787 HandleScope scope(isolate);
7788 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007789 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007790 RUNTIME_ASSERT(args[3]->IsNumber());
7791 Handle<Object> bindee = args.at<Object>(1);
7792
7793 // TODO(lrn): Create bound function in C++ code from premade shared info.
7794 bound_function->shared()->set_bound(true);
7795 // Get all arguments of calling function (Function.prototype.bind).
7796 int argc = 0;
7797 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7798 // Don't count the this-arg.
7799 if (argc > 0) {
7800 ASSERT(*arguments[0] == args[2]);
7801 argc--;
7802 } else {
7803 ASSERT(args[2]->IsUndefined());
7804 }
7805 // Initialize array of bindings (function, this, and any existing arguments
7806 // if the function was already bound).
7807 Handle<FixedArray> new_bindings;
7808 int i;
7809 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7810 Handle<FixedArray> old_bindings(
7811 JSFunction::cast(*bindee)->function_bindings());
7812 new_bindings =
7813 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7814 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7815 i = 0;
7816 for (int n = old_bindings->length(); i < n; i++) {
7817 new_bindings->set(i, old_bindings->get(i));
7818 }
7819 } else {
7820 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7821 new_bindings = isolate->factory()->NewFixedArray(array_size);
7822 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7823 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7824 i = 2;
7825 }
7826 // Copy arguments, skipping the first which is "this_arg".
7827 for (int j = 0; j < argc; j++, i++) {
7828 new_bindings->set(i, *arguments[j + 1]);
7829 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007830 new_bindings->set_map_no_write_barrier(
7831 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007832 bound_function->set_function_bindings(*new_bindings);
7833
7834 // Update length.
7835 Handle<String> length_symbol = isolate->factory()->length_symbol();
7836 Handle<Object> new_length(args.at<Object>(3));
7837 PropertyAttributes attr =
7838 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7839 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7840 return *bound_function;
7841}
7842
7843
7844RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7845 HandleScope handles(isolate);
7846 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007847 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007848 if (callable->IsJSFunction()) {
7849 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7850 if (function->shared()->bound()) {
7851 Handle<FixedArray> bindings(function->function_bindings());
7852 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7853 return *isolate->factory()->NewJSArrayWithElements(bindings);
7854 }
7855 }
7856 return isolate->heap()->undefined_value();
7857}
7858
7859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007860RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007861 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007862 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007863 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007864 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007865 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007866
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007867 // The argument is a bound function. Extract its bound arguments
7868 // and callable.
7869 Handle<FixedArray> bound_args =
7870 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7871 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7872 Handle<Object> bound_function(
7873 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7874 ASSERT(!bound_function->IsJSFunction() ||
7875 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007877 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007878 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007879 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007880 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007881 param_data[i] = Handle<Object>(bound_args->get(
7882 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007883 }
7884
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007885 if (!bound_function->IsJSFunction()) {
7886 bool exception_thrown;
7887 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7888 &exception_thrown);
7889 if (exception_thrown) return Failure::Exception();
7890 }
7891 ASSERT(bound_function->IsJSFunction());
7892
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007893 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007894 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007895 Execution::New(Handle<JSFunction>::cast(bound_function),
7896 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007897 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007898 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007899 }
7900 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007901 return *result;
7902}
7903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007904
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007905static void TrySettingInlineConstructStub(Isolate* isolate,
7906 Handle<JSFunction> function) {
7907 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007908 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007909 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007910 }
7911 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007912 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007913 Handle<Code> code = compiler.CompileConstructStub(function);
7914 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007915 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007916}
7917
7918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007919RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007920 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007921 ASSERT(args.length() == 1);
7922
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007923 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007925 // If the constructor isn't a proper function we throw a type error.
7926 if (!constructor->IsJSFunction()) {
7927 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7928 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007929 isolate->factory()->NewTypeError("not_constructor", arguments);
7930 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007931 }
7932
7933 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007934
7935 // If function should not have prototype, construction is not allowed. In this
7936 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007937 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007938 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7939 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007940 isolate->factory()->NewTypeError("not_constructor", arguments);
7941 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007942 }
7943
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007944#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007945 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007946 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 if (debug->StepInActive()) {
7948 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007949 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007950#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007951
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007952 if (function->has_initial_map()) {
7953 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954 // The 'Function' function ignores the receiver object when
7955 // called using 'new' and creates a new JSFunction object that
7956 // is returned. The receiver object is only used for error
7957 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007958 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007959 // allocate JSFunctions since it does not properly initialize
7960 // the shared part of the function. Since the receiver is
7961 // ignored anyway, we use the global object as the receiver
7962 // instead of a new JSFunction object. This way, errors are
7963 // reported the same way whether or not 'Function' is called
7964 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007965 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007967 }
7968
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007969 // The function should be compiled for the optimization hints to be
7970 // available. We cannot use EnsureCompiled because that forces a
7971 // compilation through the shared function info which makes it
7972 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007973 if (!function->is_compiled()) {
7974 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7975 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007976
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007977 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007978 if (!function->has_initial_map() &&
7979 shared->IsInobjectSlackTrackingInProgress()) {
7980 // The tracking is already in progress for another function. We can only
7981 // track one initial_map at a time, so we force the completion before the
7982 // function is called as a constructor for the first time.
7983 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007984 }
7985
7986 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007987 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7988 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007989 // Delay setting the stub if inobject slack tracking is in progress.
7990 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007992 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 isolate->counters()->constructed_objects()->Increment();
7995 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007996
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007997 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007998}
7999
8000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008001RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008002 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008003 ASSERT(args.length() == 1);
8004
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008005 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008006 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008008
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008009 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008010}
8011
8012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008013RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015 ASSERT(args.length() == 1);
8016
8017 Handle<JSFunction> function = args.at<JSFunction>(0);
8018#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008019 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008020 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008021 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008022 PrintF("]\n");
8023 }
8024#endif
8025
lrn@chromium.org34e60782011-09-15 07:25:40 +00008026 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008028 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029 return Failure::Exception();
8030 }
8031
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008032 // All done. Return the compiled code.
8033 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008034 return function->code();
8035}
8036
8037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008038RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008039 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008040 ASSERT(args.length() == 1);
8041 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008042
8043 // If the function is not compiled ignore the lazy
8044 // recompilation. This can happen if the debugger is activated and
8045 // the function is returned to the not compiled state.
8046 if (!function->shared()->is_compiled()) {
8047 function->ReplaceCode(function->shared()->code());
8048 return function->code();
8049 }
8050
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008051 // If the function is not optimizable or debugger is active continue using the
8052 // code from the full compiler.
8053 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008054 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008055 if (FLAG_trace_opt) {
8056 PrintF("[failed to optimize ");
8057 function->PrintName();
8058 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8059 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008060 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008061 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008062 function->ReplaceCode(function->shared()->code());
8063 return function->code();
8064 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00008065 function->shared()->code()->set_profiler_ticks(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008066 if (JSFunction::CompileOptimized(function,
8067 AstNode::kNoNumber,
8068 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008069 return function->code();
8070 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008071 if (FLAG_trace_opt) {
8072 PrintF("[failed to optimize ");
8073 function->PrintName();
8074 PrintF(": optimized compilation failed]\n");
8075 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008076 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008077 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008078}
8079
8080
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008081class ActivationsFinder : public ThreadVisitor {
8082 public:
8083 explicit ActivationsFinder(JSFunction* function)
8084 : function_(function), has_activations_(false) {}
8085
8086 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8087 if (has_activations_) return;
8088
8089 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8090 JavaScriptFrame* frame = it.frame();
8091 if (frame->is_optimized() && frame->function() == function_) {
8092 has_activations_ = true;
8093 return;
8094 }
8095 }
8096 }
8097
8098 bool has_activations() { return has_activations_; }
8099
8100 private:
8101 JSFunction* function_;
8102 bool has_activations_;
8103};
8104
8105
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008106static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8107 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008109 Handle<Object> arguments;
8110 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008111 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008112 if (arguments.is_null()) {
8113 // FunctionGetArguments can't throw an exception, so cast away the
8114 // doubt with an assert.
8115 arguments = Handle<Object>(
8116 Accessors::FunctionGetArguments(*function,
8117 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008118 ASSERT(*arguments != isolate->heap()->null_value());
8119 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008120 }
8121 frame->SetExpression(i, *arguments);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00008122 if (FLAG_trace_deopt) {
8123 PrintF("Materializing arguments object for frame %p - %p: %p ",
8124 reinterpret_cast<void*>(frame->sp()),
8125 reinterpret_cast<void*>(frame->fp()),
8126 reinterpret_cast<void*>(*arguments));
8127 arguments->ShortPrint();
8128 PrintF("\n");
8129 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008130 }
8131 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008132}
8133
8134
8135RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8136 HandleScope scope(isolate);
8137 ASSERT(args.length() == 1);
8138 RUNTIME_ASSERT(args[0]->IsSmi());
8139 Deoptimizer::BailoutType type =
8140 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8141 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8142 ASSERT(isolate->heap()->IsAllocationAllowed());
8143 int jsframes = deoptimizer->jsframe_count();
8144
8145 deoptimizer->MaterializeHeapNumbers();
8146 delete deoptimizer;
8147
8148 JavaScriptFrameIterator it(isolate);
8149 for (int i = 0; i < jsframes - 1; i++) {
8150 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8151 it.Advance();
8152 }
8153
8154 JavaScriptFrame* frame = it.frame();
8155 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8156 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8157 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008158
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008159 if (type == Deoptimizer::EAGER) {
8160 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008161 }
8162
8163 // Avoid doing too much work when running with --always-opt and keep
8164 // the optimized code around.
8165 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008166 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008167 }
8168
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008169 // Find other optimized activations of the function.
8170 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008171 while (!it.done()) {
8172 JavaScriptFrame* frame = it.frame();
8173 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008174 has_other_activations = true;
8175 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008176 }
8177 it.Advance();
8178 }
8179
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008180 if (!has_other_activations) {
8181 ActivationsFinder activations_finder(*function);
8182 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8183 has_other_activations = activations_finder.has_activations();
8184 }
8185
8186 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008187 if (FLAG_trace_deopt) {
8188 PrintF("[removing optimized code for: ");
8189 function->PrintName();
8190 PrintF("]\n");
8191 }
8192 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008193 } else {
8194 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008195 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008196 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008197}
8198
8199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008200RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008202 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204}
8205
8206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008207RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008209 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008210 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008211 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008212
8213 Deoptimizer::DeoptimizeFunction(*function);
8214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008215 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008216}
8217
8218
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008219RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8220#if defined(USE_SIMULATOR)
8221 return isolate->heap()->true_value();
8222#else
8223 return isolate->heap()->false_value();
8224#endif
8225}
8226
8227
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008228RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8229 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008230 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008231 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008232
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008233 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8234 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008235
8236 Code* unoptimized = function->shared()->code();
8237 if (args.length() == 2 &&
8238 unoptimized->kind() == Code::FUNCTION) {
8239 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8240 CHECK(type->IsEqualTo(CStrVector("osr")));
8241 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8242 unoptimized->set_allow_osr_at_loop_nesting_level(
8243 Code::kMaxLoopNestingMarker);
8244 }
8245
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008246 return isolate->heap()->undefined_value();
8247}
8248
8249
lrn@chromium.org1c092762011-05-09 09:42:16 +00008250RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8251 HandleScope scope(isolate);
8252 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008253 // The least significant bit (after untagging) indicates whether the
8254 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008255 if (!V8::UseCrankshaft()) {
8256 return Smi::FromInt(4); // 4 == "never".
8257 }
8258 if (FLAG_always_opt) {
8259 return Smi::FromInt(3); // 3 == "always".
8260 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008261 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008262 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8263 : Smi::FromInt(2); // 2 == "no".
8264}
8265
8266
8267RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8268 HandleScope scope(isolate);
8269 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008270 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008271 return Smi::FromInt(function->shared()->opt_count());
8272}
8273
8274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008275RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008276 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008277 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008278 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008279
8280 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008281 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008282
8283 // We have hit a back edge in an unoptimized frame for a function that was
8284 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008286 // Keep track of whether we've succeeded in optimizing.
8287 bool succeeded = unoptimized->optimizable();
8288 if (succeeded) {
8289 // If we are trying to do OSR when there are already optimized
8290 // activations of the function, it means (a) the function is directly or
8291 // indirectly recursive and (b) an optimized invocation has been
8292 // deoptimized so that we are currently in an unoptimized activation.
8293 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008294 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008295 while (succeeded && !it.done()) {
8296 JavaScriptFrame* frame = it.frame();
8297 succeeded = !frame->is_optimized() || frame->function() != *function;
8298 it.Advance();
8299 }
8300 }
8301
8302 int ast_id = AstNode::kNoNumber;
8303 if (succeeded) {
8304 // The top JS function is this one, the PC is somewhere in the
8305 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008306 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008307 JavaScriptFrame* frame = it.frame();
8308 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008309 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008310 ASSERT(unoptimized->contains(frame->pc()));
8311
8312 // Use linear search of the unoptimized code's stack check table to find
8313 // the AST id matching the PC.
8314 Address start = unoptimized->instruction_start();
8315 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008316 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008317 uint32_t table_length = Memory::uint32_at(table_cursor);
8318 table_cursor += kIntSize;
8319 for (unsigned i = 0; i < table_length; ++i) {
8320 // Table entries are (AST id, pc offset) pairs.
8321 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8322 if (pc_offset == target_pc_offset) {
8323 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8324 break;
8325 }
8326 table_cursor += 2 * kIntSize;
8327 }
8328 ASSERT(ast_id != AstNode::kNoNumber);
8329 if (FLAG_trace_osr) {
8330 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8331 function->PrintName();
8332 PrintF("]\n");
8333 }
8334
8335 // Try to compile the optimized code. A true return value from
8336 // CompileOptimized means that compilation succeeded, not necessarily
8337 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008338 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008339 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008340 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8341 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008342 if (data->OsrPcOffset()->value() >= 0) {
8343 if (FLAG_trace_osr) {
8344 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008345 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008346 }
8347 ASSERT(data->OsrAstId()->value() == ast_id);
8348 } else {
8349 // We may never generate the desired OSR entry if we emit an
8350 // early deoptimize.
8351 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008352 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008353 } else {
8354 succeeded = false;
8355 }
8356 }
8357
8358 // Revert to the original stack checks in the original unoptimized code.
8359 if (FLAG_trace_osr) {
8360 PrintF("[restoring original stack checks in ");
8361 function->PrintName();
8362 PrintF("]\n");
8363 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008364 Handle<Code> check_code;
yangguo@chromium.org56454712012-02-16 15:33:53 +00008365 if (FLAG_count_based_interrupts) {
8366 InterruptStub interrupt_stub;
8367 check_code = interrupt_stub.GetCode();
8368 } else // NOLINT
yangguo@chromium.org56454712012-02-16 15:33:53 +00008369 { // NOLINT
8370 StackCheckStub check_stub;
8371 check_code = check_stub.GetCode();
8372 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008373 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008374 Deoptimizer::RevertStackCheckCode(*unoptimized,
8375 *check_code,
8376 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008377
8378 // Allow OSR only at nesting level zero again.
8379 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8380
8381 // If the optimization attempt succeeded, return the AST id tagged as a
8382 // smi. This tells the builtin that we need to translate the unoptimized
8383 // frame to an optimized one.
8384 if (succeeded) {
8385 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8386 return Smi::FromInt(ast_id);
8387 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008388 if (function->IsMarkedForLazyRecompilation()) {
8389 function->ReplaceCode(function->shared()->code());
8390 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008391 return Smi::FromInt(-1);
8392 }
8393}
8394
8395
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008396RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8397 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8398 return isolate->heap()->undefined_value();
8399}
8400
8401
danno@chromium.orgc612e022011-11-10 11:38:15 +00008402RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8403 HandleScope scope(isolate);
8404 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008405 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008406 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8407 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008408
8409 // If there are too many arguments, allocate argv via malloc.
8410 const int argv_small_size = 10;
8411 Handle<Object> argv_small_buffer[argv_small_size];
8412 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8413 Handle<Object>* argv = argv_small_buffer;
8414 if (argc > argv_small_size) {
8415 argv = new Handle<Object>[argc];
8416 if (argv == NULL) return isolate->StackOverflow();
8417 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8418 }
8419
8420 for (int i = 0; i < argc; ++i) {
8421 MaybeObject* maybe = args[1 + i];
8422 Object* object;
8423 if (!maybe->To<Object>(&object)) return maybe;
8424 argv[i] = Handle<Object>(object);
8425 }
8426
8427 bool threw;
8428 Handle<JSReceiver> hfun(fun);
8429 Handle<Object> hreceiver(receiver);
8430 Handle<Object> result =
8431 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8432
8433 if (threw) return Failure::Exception();
8434 return *result;
8435}
8436
8437
lrn@chromium.org34e60782011-09-15 07:25:40 +00008438RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8439 HandleScope scope(isolate);
8440 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008441 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008442 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008443 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008444 CONVERT_SMI_ARG_CHECKED(offset, 3);
8445 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008446 ASSERT(offset >= 0);
8447 ASSERT(argc >= 0);
8448
8449 // If there are too many arguments, allocate argv via malloc.
8450 const int argv_small_size = 10;
8451 Handle<Object> argv_small_buffer[argv_small_size];
8452 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8453 Handle<Object>* argv = argv_small_buffer;
8454 if (argc > argv_small_size) {
8455 argv = new Handle<Object>[argc];
8456 if (argv == NULL) return isolate->StackOverflow();
8457 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8458 }
8459
8460 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008461 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008462 }
8463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008464 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008465 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008466 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008467
8468 if (threw) return Failure::Exception();
8469 return *result;
8470}
8471
8472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008473RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008474 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008475 ASSERT(args.length() == 1);
8476 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8477 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8478}
8479
8480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008481RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008482 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008483 ASSERT(args.length() == 1);
8484 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8485 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8486}
8487
8488
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008489RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008491 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008492
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008493 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008494 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008495 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008496 { MaybeObject* maybe_result =
8497 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008498 if (!maybe_result->ToObject(&result)) return maybe_result;
8499 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008501 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008502
kasper.lund7276f142008-07-30 08:49:36 +00008503 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008504}
8505
lrn@chromium.org303ada72010-10-27 09:33:13 +00008506
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008507RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8508 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008509 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008510 JSObject* extension_object;
8511 if (args[0]->IsJSObject()) {
8512 extension_object = JSObject::cast(args[0]);
8513 } else {
8514 // Convert the object to a proper JavaScript object.
8515 MaybeObject* maybe_js_object = args[0]->ToObject();
8516 if (!maybe_js_object->To(&extension_object)) {
8517 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8518 HandleScope scope(isolate);
8519 Handle<Object> handle = args.at<Object>(0);
8520 Handle<Object> result =
8521 isolate->factory()->NewTypeError("with_expression",
8522 HandleVector(&handle, 1));
8523 return isolate->Throw(*result);
8524 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008525 return maybe_js_object;
8526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008527 }
8528 }
8529
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008530 JSFunction* function;
8531 if (args[1]->IsSmi()) {
8532 // A smi sentinel indicates a context nested inside global code rather
8533 // than some function. There is a canonical empty function that can be
8534 // gotten from the global context.
8535 function = isolate->context()->global_context()->closure();
8536 } else {
8537 function = JSFunction::cast(args[1]);
8538 }
8539
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008540 Context* context;
8541 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008542 isolate->heap()->AllocateWithContext(function,
8543 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008544 extension_object);
8545 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008546 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008547 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008548}
8549
8550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008551RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008552 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008553 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008554 String* name = String::cast(args[0]);
8555 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008556 JSFunction* function;
8557 if (args[2]->IsSmi()) {
8558 // A smi sentinel indicates a context nested inside global code rather
8559 // than some function. There is a canonical empty function that can be
8560 // gotten from the global context.
8561 function = isolate->context()->global_context()->closure();
8562 } else {
8563 function = JSFunction::cast(args[2]);
8564 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008565 Context* context;
8566 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008567 isolate->heap()->AllocateCatchContext(function,
8568 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008569 name,
8570 thrown_object);
8571 if (!maybe_context->To(&context)) return maybe_context;
8572 isolate->set_context(context);
8573 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008574}
8575
8576
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008577RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8578 NoHandleAllocation ha;
8579 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008580 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008581 JSFunction* function;
8582 if (args[1]->IsSmi()) {
8583 // A smi sentinel indicates a context nested inside global code rather
8584 // than some function. There is a canonical empty function that can be
8585 // gotten from the global context.
8586 function = isolate->context()->global_context()->closure();
8587 } else {
8588 function = JSFunction::cast(args[1]);
8589 }
8590 Context* context;
8591 MaybeObject* maybe_context =
8592 isolate->heap()->AllocateBlockContext(function,
8593 isolate->context(),
8594 scope_info);
8595 if (!maybe_context->To(&context)) return maybe_context;
8596 isolate->set_context(context);
8597 return context;
8598}
8599
8600
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008601RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
8602 NoHandleAllocation ha;
8603 ASSERT(args.length() == 2);
8604 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 0);
8605 CONVERT_ARG_HANDLE_CHECKED(JSModule, instance, 1);
8606
8607 Context* context;
8608 MaybeObject* maybe_context =
8609 isolate->heap()->AllocateModuleContext(isolate->context(),
8610 scope_info);
8611 if (!maybe_context->To(&context)) return maybe_context;
8612 // Also initialize the context slot of the instance object.
8613 instance->set_context(context);
8614 isolate->set_context(context);
8615
8616 return context;
8617}
8618
8619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008620RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008621 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622 ASSERT(args.length() == 2);
8623
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008624 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8625 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008626
8627 int index;
8628 PropertyAttributes attributes;
8629 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008630 BindingFlags binding_flags;
8631 Handle<Object> holder = context->Lookup(name,
8632 flags,
8633 &index,
8634 &attributes,
8635 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008637 // If the slot was not found the result is true.
8638 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008639 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008640 }
8641
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008642 // If the slot was found in a context, it should be DONT_DELETE.
8643 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008644 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008645 }
8646
8647 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008648 // the global object, or the subject of a with. Try to delete it
8649 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008650 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008651 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652}
8653
8654
ager@chromium.orga1645e22009-09-09 19:27:10 +00008655// A mechanism to return a pair of Object pointers in registers (if possible).
8656// How this is achieved is calling convention-dependent.
8657// All currently supported x86 compiles uses calling conventions that are cdecl
8658// variants where a 64-bit value is returned in two 32-bit registers
8659// (edx:eax on ia32, r1:r0 on ARM).
8660// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8661// In Win64 calling convention, a struct of two pointers is returned in memory,
8662// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008663#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008664struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008665 MaybeObject* x;
8666 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008667};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008668
lrn@chromium.org303ada72010-10-27 09:33:13 +00008669static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008670 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008671 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8672 // In Win64 they are assigned to a hidden first argument.
8673 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008674}
8675#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008676typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008677static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008679 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008680}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008681#endif
8682
8683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008684static inline MaybeObject* Unhole(Heap* heap,
8685 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008686 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8688 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690}
8691
8692
danno@chromium.org40cb8782011-05-25 07:58:50 +00008693static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8694 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008695 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008697 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008698 JSFunction* context_extension_function =
8699 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008700 // If the holder isn't a context extension object, we just return it
8701 // as the receiver. This allows arguments objects to be used as
8702 // receivers, but only if they are put in the context scope chain
8703 // explicitly via a with-statement.
8704 Object* constructor = holder->map()->constructor();
8705 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008706 // Fall back to using the global object as the implicit receiver if
8707 // the property turns out to be a local variable allocated in a
8708 // context extension object - introduced via eval. Implicit global
8709 // receivers are indicated with the hole value.
8710 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008711}
8712
8713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008714static ObjectPair LoadContextSlotHelper(Arguments args,
8715 Isolate* isolate,
8716 bool throw_error) {
8717 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008718 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008720 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008721 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008722 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008723 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008724 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008725
8726 int index;
8727 PropertyAttributes attributes;
8728 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008729 BindingFlags binding_flags;
8730 Handle<Object> holder = context->Lookup(name,
8731 flags,
8732 &index,
8733 &attributes,
8734 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008735
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008736 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008737 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008738 ASSERT(holder->IsContext());
8739 // If the "property" we were looking for is a local variable, the
8740 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008741 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008742 // Use the hole as the receiver to signal that the receiver is implicit
8743 // and that the global receiver should be used (as distinguished from an
8744 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008745 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008746 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008747 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008748 switch (binding_flags) {
8749 case MUTABLE_CHECK_INITIALIZED:
8750 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8751 if (value->IsTheHole()) {
8752 Handle<Object> reference_error =
8753 isolate->factory()->NewReferenceError("not_defined",
8754 HandleVector(&name, 1));
8755 return MakePair(isolate->Throw(*reference_error), NULL);
8756 }
8757 // FALLTHROUGH
8758 case MUTABLE_IS_INITIALIZED:
8759 case IMMUTABLE_IS_INITIALIZED:
8760 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8761 ASSERT(!value->IsTheHole());
8762 return MakePair(value, *receiver);
8763 case IMMUTABLE_CHECK_INITIALIZED:
8764 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8765 case MISSING_BINDING:
8766 UNREACHABLE();
8767 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008768 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769 }
8770
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008771 // Otherwise, if the slot was found the holder is a context extension
8772 // object, subject of a with, or a global object. We read the named
8773 // property from it.
8774 if (!holder.is_null()) {
8775 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8776 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008777 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008778 Handle<Object> receiver_handle(object->IsGlobalObject()
8779 ? GlobalObject::cast(*object)->global_receiver()
8780 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008781
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008782 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008783 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008784 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008785 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008786 }
8787
8788 if (throw_error) {
8789 // The property doesn't exist - throw exception.
8790 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 isolate->factory()->NewReferenceError("not_defined",
8792 HandleVector(&name, 1));
8793 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008794 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008795 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008796 return MakePair(isolate->heap()->undefined_value(),
8797 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798 }
8799}
8800
8801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008802RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008803 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008804}
8805
8806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008807RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008808 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008809}
8810
8811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008812RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008813 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008814 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008816 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008817 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8818 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008819 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8820 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8821 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008822
8823 int index;
8824 PropertyAttributes attributes;
8825 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008826 BindingFlags binding_flags;
8827 Handle<Object> holder = context->Lookup(name,
8828 flags,
8829 &index,
8830 &attributes,
8831 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832
8833 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008834 // The property was found in a context slot.
8835 Handle<Context> context = Handle<Context>::cast(holder);
8836 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8837 context->get(index)->IsTheHole()) {
8838 Handle<Object> error =
8839 isolate->factory()->NewReferenceError("not_defined",
8840 HandleVector(&name, 1));
8841 return isolate->Throw(*error);
8842 }
8843 // Ignore if read_only variable.
8844 if ((attributes & READ_ONLY) == 0) {
8845 // Context is a fixed array and set cannot fail.
8846 context->set(index, *value);
8847 } else if (strict_mode == kStrictMode) {
8848 // Setting read only property in strict mode.
8849 Handle<Object> error =
8850 isolate->factory()->NewTypeError("strict_cannot_assign",
8851 HandleVector(&name, 1));
8852 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 }
8854 return *value;
8855 }
8856
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008857 // Slow case: The property is not in a context slot. It is either in a
8858 // context extension object, a property of the subject of a with, or a
8859 // property of the global object.
8860 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008861
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008862 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008863 // The property exists on the holder.
8864 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008866 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008867 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008868
8869 if (strict_mode == kStrictMode) {
8870 // Throw in strict mode (assignment to undefined variable).
8871 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008872 isolate->factory()->NewReferenceError(
8873 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008874 return isolate->Throw(*error);
8875 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008876 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008878 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879 }
8880
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008881 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008882 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008883 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008884 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008885 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008886 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008887 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008888 // Setting read only property in strict mode.
8889 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 isolate->factory()->NewTypeError(
8891 "strict_cannot_assign", HandleVector(&name, 1));
8892 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008893 }
8894 return *value;
8895}
8896
8897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008898RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008899 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008900 ASSERT(args.length() == 1);
8901
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008902 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008903}
8904
8905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008906RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008908 ASSERT(args.length() == 1);
8909
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008910 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008911}
8912
8913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008914RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008915 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008916 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008917}
8918
8919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008920RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008921 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 ASSERT(args.length() == 1);
8923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008924 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008926 isolate->factory()->NewReferenceError("not_defined",
8927 HandleVector(&name, 1));
8928 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008929}
8930
8931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008932RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008933 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934
8935 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008936 if (isolate->stack_guard()->IsStackOverflow()) {
8937 NoHandleAllocation na;
8938 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940
ulan@chromium.org812308e2012-02-29 15:58:45 +00008941 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008942}
8943
8944
yangguo@chromium.org56454712012-02-16 15:33:53 +00008945RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8946 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008947 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008948}
8949
8950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951static int StackSize() {
8952 int n = 0;
8953 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8954 return n;
8955}
8956
8957
8958static void PrintTransition(Object* result) {
8959 // indentation
8960 { const int nmax = 80;
8961 int n = StackSize();
8962 if (n <= nmax)
8963 PrintF("%4d:%*s", n, n, "");
8964 else
8965 PrintF("%4d:%*s", n, nmax, "...");
8966 }
8967
8968 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008969 JavaScriptFrame::PrintTop(stdout, true, false);
8970 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971 } else {
8972 // function result
8973 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008974 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975 PrintF("\n");
8976 }
8977}
8978
8979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008980RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008981 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 NoHandleAllocation ha;
8983 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985}
8986
8987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008988RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008989 NoHandleAllocation ha;
8990 PrintTransition(args[0]);
8991 return args[0]; // return TOS
8992}
8993
8994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008995RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008996 NoHandleAllocation ha;
8997 ASSERT(args.length() == 1);
8998
8999#ifdef DEBUG
9000 if (args[0]->IsString()) {
9001 // If we have a string, assume it's a code "marker"
9002 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009003 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009005 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9006 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007 } else {
9008 PrintF("DebugPrint: ");
9009 }
9010 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009011 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009012 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009013 HeapObject::cast(args[0])->map()->Print();
9014 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009015#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009016 // ShortPrint is available in release mode. Print is not.
9017 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009018#endif
9019 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009020 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021
9022 return args[0]; // return TOS
9023}
9024
9025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009026RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009027 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009028 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009029 isolate->PrintStack();
9030 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031}
9032
9033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009034RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009036 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037
9038 // According to ECMA-262, section 15.9.1, page 117, the precision of
9039 // the number in a Date object representing a particular instant in
9040 // time is milliseconds. Therefore, we floor the result of getting
9041 // the OS time.
9042 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009043 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009044}
9045
9046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009047RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009048 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009049 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009051 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009052 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009054 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009055
9056 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009057 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009058 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009059 RUNTIME_ASSERT(output->HasFastElements());
9060
9061 AssertNoAllocation no_allocation;
9062
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009063 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009064 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9065 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009066 String::FlatContent str_content = str->GetFlatContent();
9067 if (str_content.IsAscii()) {
9068 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009069 output_array,
9070 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009072 ASSERT(str_content.IsTwoByte());
9073 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009074 output_array,
9075 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009076 }
9077
9078 if (result) {
9079 return *output;
9080 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082 }
9083}
9084
9085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009086RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009087 NoHandleAllocation ha;
9088 ASSERT(args.length() == 1);
9089
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009090 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009091 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9092 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009093 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094}
9095
9096
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009097RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 NoHandleAllocation ha;
9099 ASSERT(args.length() == 1);
9100
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009101 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009102 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9103
9104 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105}
9106
9107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009108RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009109 ASSERT(args.length() == 1);
9110 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009112 return JSGlobalObject::cast(global)->global_receiver();
9113}
9114
9115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009116RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009117 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009118 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009119 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009120
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009121 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009122 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009123 Handle<Object> result;
9124 if (source->IsSeqAsciiString()) {
9125 result = JsonParser<true>::Parse(source);
9126 } else {
9127 result = JsonParser<false>::Parse(source);
9128 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009129 if (result.is_null()) {
9130 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009131 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009132 return Failure::Exception();
9133 }
9134 return *result;
9135}
9136
9137
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009138bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9139 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009140 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9141 // Check with callback if set.
9142 AllowCodeGenerationFromStringsCallback callback =
9143 isolate->allow_code_gen_callback();
9144 if (callback == NULL) {
9145 // No callback set and code generation disallowed.
9146 return false;
9147 } else {
9148 // Callback set. Let it decide if code generation is allowed.
9149 VMState state(isolate, EXTERNAL);
9150 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009151 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009152}
9153
9154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009155RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009157 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009158 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009159
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009160 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009161 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009162
9163 // Check if global context allows code generation from
9164 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009165 if (context->allow_code_gen_from_strings()->IsFalse() &&
9166 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009167 return isolate->Throw(*isolate->factory()->NewError(
9168 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9169 }
9170
9171 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009172 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009173 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009174 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009176 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9177 context,
9178 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179 return *fun;
9180}
9181
9182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009183static ObjectPair CompileGlobalEval(Isolate* isolate,
9184 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009185 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009186 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009187 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009188 Handle<Context> context = Handle<Context>(isolate->context());
9189 Handle<Context> global_context = Handle<Context>(context->global_context());
9190
9191 // Check if global context allows code generation from
9192 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009193 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9194 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009195 isolate->Throw(*isolate->factory()->NewError(
9196 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9197 return MakePair(Failure::Exception(), NULL);
9198 }
9199
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009200 // Deal with a normal eval call with a string argument. Compile it
9201 // and return the compiled function bound in the local context.
9202 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9203 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009204 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009205 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009206 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009207 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009208 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009209 Handle<JSFunction> compiled =
9210 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009211 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009212 return MakePair(*compiled, *receiver);
9213}
9214
9215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009216RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009217 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009218
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009219 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009220 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009221
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009222 // If "eval" didn't refer to the original GlobalEval, it's not a
9223 // direct call to eval.
9224 // (And even if it is, but the first argument isn't a string, just let
9225 // execution default to an indirect call to eval, which will also return
9226 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009228 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009229 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009230 }
9231
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009232 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009233 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 return CompileGlobalEval(isolate,
9235 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009236 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009237 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009238 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009239}
9240
9241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009242RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009243 // This utility adjusts the property attributes for newly created Function
9244 // object ("new Function(...)") by changing the map.
9245 // All it does is changing the prototype property to enumerable
9246 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009249 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009251 Handle<Map> map = func->shared()->is_classic_mode()
9252 ? isolate->function_instance_map()
9253 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254
9255 ASSERT(func->map()->instance_type() == map->instance_type());
9256 ASSERT(func->map()->instance_size() == map->instance_size());
9257 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258 return *func;
9259}
9260
9261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009262RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009263 // Allocate a block of memory in NewSpace (filled with a filler).
9264 // Use as fallback for allocation in generated code when NewSpace
9265 // is full.
9266 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009267 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009268 int size = size_smi->value();
9269 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9270 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009271 Heap* heap = isolate->heap();
9272 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009273 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009274 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009275 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009276 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009277 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009278 }
9279 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009280 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009281}
9282
9283
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009284// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009285// array. Returns true if the element was pushed on the stack and
9286// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009287RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009288 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009289 CONVERT_ARG_CHECKED(JSArray, array, 0);
9290 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009291 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009292 int length = Smi::cast(array->length())->value();
9293 FixedArray* elements = FixedArray::cast(array->elements());
9294 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009295 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009296 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009297 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009298 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009299 { MaybeObject* maybe_obj =
9300 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009301 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9302 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009303 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009304}
9305
9306
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009307/**
9308 * A simple visitor visits every element of Array's.
9309 * The backend storage can be a fixed array for fast elements case,
9310 * or a dictionary for sparse array. Since Dictionary is a subtype
9311 * of FixedArray, the class can be used by both fast and slow cases.
9312 * The second parameter of the constructor, fast_elements, specifies
9313 * whether the storage is a FixedArray or Dictionary.
9314 *
9315 * An index limit is used to deal with the situation that a result array
9316 * length overflows 32-bit non-negative integer.
9317 */
9318class ArrayConcatVisitor {
9319 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009320 ArrayConcatVisitor(Isolate* isolate,
9321 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009322 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 isolate_(isolate),
9324 storage_(Handle<FixedArray>::cast(
9325 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009326 index_offset_(0u),
9327 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009328
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009329 ~ArrayConcatVisitor() {
9330 clear_storage();
9331 }
9332
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009333 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009334 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009335 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009336
9337 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009338 if (index < static_cast<uint32_t>(storage_->length())) {
9339 storage_->set(index, *elm);
9340 return;
9341 }
9342 // Our initial estimate of length was foiled, possibly by
9343 // getters on the arrays increasing the length of later arrays
9344 // during iteration.
9345 // This shouldn't happen in anything but pathological cases.
9346 SetDictionaryMode(index);
9347 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009348 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009349 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009350 Handle<SeededNumberDictionary> dict(
9351 SeededNumberDictionary::cast(*storage_));
9352 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009354 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009355 // Dictionary needed to grow.
9356 clear_storage();
9357 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009358 }
9359}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009360
9361 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009362 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9363 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009364 } else {
9365 index_offset_ += delta;
9366 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009367 }
9368
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009369 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009371 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009373 Handle<Map> map;
9374 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009375 map = isolate_->factory()->GetElementsTransitionMap(array,
9376 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009377 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009378 map = isolate_->factory()->GetElementsTransitionMap(array,
9379 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009380 }
9381 array->set_map(*map);
9382 array->set_length(*length);
9383 array->set_elements(*storage_);
9384 return array;
9385 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009386
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009387 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009388 // Convert storage to dictionary mode.
9389 void SetDictionaryMode(uint32_t index) {
9390 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009391 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009392 Handle<SeededNumberDictionary> slow_storage(
9393 isolate_->factory()->NewSeededNumberDictionary(
9394 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009395 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9396 for (uint32_t i = 0; i < current_length; i++) {
9397 HandleScope loop_scope;
9398 Handle<Object> element(current_storage->get(i));
9399 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009400 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009401 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009402 if (!new_storage.is_identical_to(slow_storage)) {
9403 slow_storage = loop_scope.CloseAndEscape(new_storage);
9404 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009405 }
9406 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009407 clear_storage();
9408 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009409 fast_elements_ = false;
9410 }
9411
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009412 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009413 isolate_->global_handles()->Destroy(
9414 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009415 }
9416
9417 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 storage_ = Handle<FixedArray>::cast(
9419 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009420 }
9421
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009422 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009423 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009424 // Index after last seen index. Always less than or equal to
9425 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009426 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009427 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009428};
9429
9430
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009431static uint32_t EstimateElementCount(Handle<JSArray> array) {
9432 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9433 int element_count = 0;
9434 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009435 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009436 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009437 // Fast elements can't have lengths that are not representable by
9438 // a 32-bit signed integer.
9439 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9440 int fast_length = static_cast<int>(length);
9441 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9442 for (int i = 0; i < fast_length; i++) {
9443 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009444 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009445 break;
9446 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009447 case FAST_DOUBLE_ELEMENTS:
9448 // TODO(1810): Decide if it's worthwhile to implement this.
9449 UNREACHABLE();
9450 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009451 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009452 Handle<SeededNumberDictionary> dictionary(
9453 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009454 int capacity = dictionary->Capacity();
9455 for (int i = 0; i < capacity; i++) {
9456 Handle<Object> key(dictionary->KeyAt(i));
9457 if (dictionary->IsKey(*key)) {
9458 element_count++;
9459 }
9460 }
9461 break;
9462 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009463 case NON_STRICT_ARGUMENTS_ELEMENTS:
9464 case EXTERNAL_BYTE_ELEMENTS:
9465 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9466 case EXTERNAL_SHORT_ELEMENTS:
9467 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9468 case EXTERNAL_INT_ELEMENTS:
9469 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9470 case EXTERNAL_FLOAT_ELEMENTS:
9471 case EXTERNAL_DOUBLE_ELEMENTS:
9472 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009473 // External arrays are always dense.
9474 return length;
9475 }
9476 // As an estimate, we assume that the prototype doesn't contain any
9477 // inherited elements.
9478 return element_count;
9479}
9480
9481
9482
9483template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484static void IterateExternalArrayElements(Isolate* isolate,
9485 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009486 bool elements_are_ints,
9487 bool elements_are_guaranteed_smis,
9488 ArrayConcatVisitor* visitor) {
9489 Handle<ExternalArrayClass> array(
9490 ExternalArrayClass::cast(receiver->elements()));
9491 uint32_t len = static_cast<uint32_t>(array->length());
9492
9493 ASSERT(visitor != NULL);
9494 if (elements_are_ints) {
9495 if (elements_are_guaranteed_smis) {
9496 for (uint32_t j = 0; j < len; j++) {
9497 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009498 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009499 visitor->visit(j, e);
9500 }
9501 } else {
9502 for (uint32_t j = 0; j < len; j++) {
9503 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009504 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009505 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9506 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9507 visitor->visit(j, e);
9508 } else {
9509 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009510 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009511 visitor->visit(j, e);
9512 }
9513 }
9514 }
9515 } else {
9516 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009517 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009518 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009519 visitor->visit(j, e);
9520 }
9521 }
9522}
9523
9524
9525// Used for sorting indices in a List<uint32_t>.
9526static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9527 uint32_t a = *ap;
9528 uint32_t b = *bp;
9529 return (a == b) ? 0 : (a < b) ? -1 : 1;
9530}
9531
9532
9533static void CollectElementIndices(Handle<JSObject> object,
9534 uint32_t range,
9535 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009536 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009537 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009538 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009539 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009540 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9541 uint32_t length = static_cast<uint32_t>(elements->length());
9542 if (range < length) length = range;
9543 for (uint32_t i = 0; i < length; i++) {
9544 if (!elements->get(i)->IsTheHole()) {
9545 indices->Add(i);
9546 }
9547 }
9548 break;
9549 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009550 case FAST_DOUBLE_ELEMENTS: {
9551 // TODO(1810): Decide if it's worthwhile to implement this.
9552 UNREACHABLE();
9553 break;
9554 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009555 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009556 Handle<SeededNumberDictionary> dict(
9557 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009558 uint32_t capacity = dict->Capacity();
9559 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009560 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009561 Handle<Object> k(dict->KeyAt(j));
9562 if (dict->IsKey(*k)) {
9563 ASSERT(k->IsNumber());
9564 uint32_t index = static_cast<uint32_t>(k->Number());
9565 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009566 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009567 }
9568 }
9569 }
9570 break;
9571 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009572 default: {
9573 int dense_elements_length;
9574 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009575 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009576 dense_elements_length =
9577 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009578 break;
9579 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009580 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009581 dense_elements_length =
9582 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009583 break;
9584 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009585 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009586 dense_elements_length =
9587 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009588 break;
9589 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009590 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009591 dense_elements_length =
9592 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009593 break;
9594 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009595 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009596 dense_elements_length =
9597 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 break;
9599 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009600 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009601 dense_elements_length =
9602 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009603 break;
9604 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009605 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009606 dense_elements_length =
9607 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009608 break;
9609 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009610 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009611 dense_elements_length =
9612 ExternalFloatArray::cast(object->elements())->length();
9613 break;
9614 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009615 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009616 dense_elements_length =
9617 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009618 break;
9619 }
9620 default:
9621 UNREACHABLE();
9622 dense_elements_length = 0;
9623 break;
9624 }
9625 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9626 if (range <= length) {
9627 length = range;
9628 // We will add all indices, so we might as well clear it first
9629 // and avoid duplicates.
9630 indices->Clear();
9631 }
9632 for (uint32_t i = 0; i < length; i++) {
9633 indices->Add(i);
9634 }
9635 if (length == range) return; // All indices accounted for already.
9636 break;
9637 }
9638 }
9639
9640 Handle<Object> prototype(object->GetPrototype());
9641 if (prototype->IsJSObject()) {
9642 // The prototype will usually have no inherited element indices,
9643 // but we have to check.
9644 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9645 }
9646}
9647
9648
9649/**
9650 * A helper function that visits elements of a JSArray in numerical
9651 * order.
9652 *
9653 * The visitor argument called for each existing element in the array
9654 * with the element index and the element's value.
9655 * Afterwards it increments the base-index of the visitor by the array
9656 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009657 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009658 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659static bool IterateElements(Isolate* isolate,
9660 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009661 ArrayConcatVisitor* visitor) {
9662 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9663 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009664 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009665 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009666 // Run through the elements FixedArray and use HasElement and GetElement
9667 // to check the prototype for missing elements.
9668 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9669 int fast_length = static_cast<int>(length);
9670 ASSERT(fast_length <= elements->length());
9671 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009672 HandleScope loop_scope(isolate);
9673 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009674 if (!element_value->IsTheHole()) {
9675 visitor->visit(j, element_value);
9676 } else if (receiver->HasElement(j)) {
9677 // Call GetElement on receiver, not its prototype, or getters won't
9678 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009679 element_value = Object::GetElement(receiver, j);
9680 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 visitor->visit(j, element_value);
9682 }
9683 }
9684 break;
9685 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009686 case FAST_DOUBLE_ELEMENTS: {
9687 // TODO(1810): Decide if it's worthwhile to implement this.
9688 UNREACHABLE();
9689 break;
9690 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009691 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009692 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 List<uint32_t> indices(dict->Capacity() / 2);
9694 // Collect all indices in the object and the prototypes less
9695 // than length. This might introduce duplicates in the indices list.
9696 CollectElementIndices(receiver, length, &indices);
9697 indices.Sort(&compareUInt32);
9698 int j = 0;
9699 int n = indices.length();
9700 while (j < n) {
9701 HandleScope loop_scope;
9702 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009703 Handle<Object> element = Object::GetElement(receiver, index);
9704 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009705 visitor->visit(index, element);
9706 // Skip to next different index (i.e., omit duplicates).
9707 do {
9708 j++;
9709 } while (j < n && indices[j] == index);
9710 }
9711 break;
9712 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009713 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009714 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9715 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009716 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009717 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009718 visitor->visit(j, e);
9719 }
9720 break;
9721 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009722 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009724 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009725 break;
9726 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009727 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009728 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009729 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009730 break;
9731 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009732 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009733 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009734 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 break;
9736 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009737 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009738 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009739 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009740 break;
9741 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009742 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009743 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009744 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009745 break;
9746 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009747 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009749 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009750 break;
9751 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009752 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009753 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009754 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009755 break;
9756 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009757 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009758 IterateExternalArrayElements<ExternalDoubleArray, double>(
9759 isolate, receiver, false, false, visitor);
9760 break;
9761 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009762 default:
9763 UNREACHABLE();
9764 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009765 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009767 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009768}
9769
9770
9771/**
9772 * Array::concat implementation.
9773 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009774 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009775 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009776 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009777RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009778 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009780
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009781 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009782 int argument_count = static_cast<int>(arguments->length()->Number());
9783 RUNTIME_ASSERT(arguments->HasFastElements());
9784 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009785
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009786 // Pass 1: estimate the length and number of elements of the result.
9787 // The actual length can be larger if any of the arguments have getters
9788 // that mutate other arguments (but will otherwise be precise).
9789 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009790
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009791 uint32_t estimate_result_length = 0;
9792 uint32_t estimate_nof_elements = 0;
9793 {
9794 for (int i = 0; i < argument_count; i++) {
9795 HandleScope loop_scope;
9796 Handle<Object> obj(elements->get(i));
9797 uint32_t length_estimate;
9798 uint32_t element_estimate;
9799 if (obj->IsJSArray()) {
9800 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009801 // TODO(1810): Find out if it's worthwhile to properly support
9802 // arbitrary ElementsKinds. For now, pessimistically transition to
9803 // FAST_ELEMENTS.
9804 if (array->HasFastDoubleElements()) {
9805 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009806 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009807 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 length_estimate =
9809 static_cast<uint32_t>(array->length()->Number());
9810 element_estimate =
9811 EstimateElementCount(array);
9812 } else {
9813 length_estimate = 1;
9814 element_estimate = 1;
9815 }
9816 // Avoid overflows by capping at kMaxElementCount.
9817 if (JSObject::kMaxElementCount - estimate_result_length <
9818 length_estimate) {
9819 estimate_result_length = JSObject::kMaxElementCount;
9820 } else {
9821 estimate_result_length += length_estimate;
9822 }
9823 if (JSObject::kMaxElementCount - estimate_nof_elements <
9824 element_estimate) {
9825 estimate_nof_elements = JSObject::kMaxElementCount;
9826 } else {
9827 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009828 }
9829 }
9830 }
9831
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009832 // If estimated number of elements is more than half of length, a
9833 // fixed array (fast case) is more time and space-efficient than a
9834 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009836
9837 Handle<FixedArray> storage;
9838 if (fast_case) {
9839 // The backing storage array must have non-existing elements to
9840 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009841 storage = isolate->factory()->NewFixedArrayWithHoles(
9842 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009843 } else {
9844 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9845 uint32_t at_least_space_for = estimate_nof_elements +
9846 (estimate_nof_elements >> 2);
9847 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009848 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009849 }
9850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009852
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009853 for (int i = 0; i < argument_count; i++) {
9854 Handle<Object> obj(elements->get(i));
9855 if (obj->IsJSArray()) {
9856 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009857 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009858 return Failure::Exception();
9859 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009860 } else {
9861 visitor.visit(0, obj);
9862 visitor.increase_index_offset(1);
9863 }
9864 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009865
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009866 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009867}
9868
9869
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870// This will not allocate (flatten the string), but it may run
9871// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009872RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009873 NoHandleAllocation ha;
9874 ASSERT(args.length() == 1);
9875
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009876 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877 StringInputBuffer buffer(string);
9878 while (buffer.has_more()) {
9879 uint16_t character = buffer.GetNext();
9880 PrintF("%c", character);
9881 }
9882 return string;
9883}
9884
ager@chromium.org5ec48922009-05-05 07:25:34 +00009885// Moves all own elements of an object, that are below a limit, to positions
9886// starting at zero. All undefined values are placed after non-undefined values,
9887// and are followed by non-existing element. Does not change the length
9888// property.
9889// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009890RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009891 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009892 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009893 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9894 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895}
9896
9897
9898// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009899RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009900 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009901 CONVERT_ARG_CHECKED(JSArray, from, 0);
9902 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009903 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009904 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009905 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009906 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9907 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009908 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009909 } else if (new_elements->map() ==
9910 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009911 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009912 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009913 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009914 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009915 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009916 Object* new_map;
9917 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009918 to->set_map(Map::cast(new_map));
9919 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009921 Object* obj;
9922 { MaybeObject* maybe_obj = from->ResetElements();
9923 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9924 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009925 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009926 return to;
9927}
9928
9929
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009930// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009931RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009933 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009934 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009935 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009936 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9937 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009938 } else if (object->IsJSArray()) {
9939 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009940 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009941 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942 }
9943}
9944
9945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009946RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009948
9949 ASSERT_EQ(3, args.length());
9950
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009951 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009952 Handle<Object> key1 = args.at<Object>(1);
9953 Handle<Object> key2 = args.at<Object>(2);
9954
9955 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009956 if (!key1->ToArrayIndex(&index1)
9957 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009958 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009959 }
9960
ager@chromium.orgac091b72010-05-05 07:34:42 +00009961 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009962 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009963 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009964 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009965 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009966
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009967 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009968 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009969 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009970 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009971
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009972 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009973}
9974
9975
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009977// might have elements. Can either return keys (positive integers) or
9978// intervals (pair of a negative integer (-start-1) followed by a
9979// positive (length)) or undefined values.
9980// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009981RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009982 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009983 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009984 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009986 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009987 // Create an array and get all the keys into it, then remove all the
9988 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009989 bool threw = false;
9990 Handle<FixedArray> keys =
9991 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9992 if (threw) return Failure::Exception();
9993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009994 int keys_length = keys->length();
9995 for (int i = 0; i < keys_length; i++) {
9996 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009997 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009998 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999 // Zap invalid keys.
10000 keys->set_undefined(i);
10001 }
10002 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010003 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010005 ASSERT(array->HasFastElements() ||
10006 array->HasFastSmiOnlyElements() ||
10007 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010010 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010011 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010012 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010013 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010014 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010015 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010016 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010017 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010018 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019 }
10020}
10021
10022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010023RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010025 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10026 CONVERT_ARG_CHECKED(String, name, 1);
10027 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010028 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10029 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010030}
10031
10032
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010033#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010034RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010035 ASSERT(args.length() == 0);
10036 return Execution::DebugBreakHelper();
10037}
10038
10039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040// Helper functions for wrapping and unwrapping stack frame ids.
10041static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010042 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010043 return Smi::FromInt(id >> 2);
10044}
10045
10046
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010047static StackFrame::Id UnwrapFrameId(int wrapped) {
10048 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010049}
10050
10051
10052// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010053// args[0]: debug event listener function to set or null or undefined for
10054// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010056RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010057 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010058 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10059 args[0]->IsUndefined() ||
10060 args[0]->IsNull());
10061 Handle<Object> callback = args.at<Object>(0);
10062 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010063 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010064
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010065 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010066}
10067
10068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010069RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010070 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010071 isolate->stack_guard()->DebugBreak();
10072 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073}
10074
10075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010076static MaybeObject* DebugLookupResultValue(Heap* heap,
10077 Object* receiver,
10078 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010079 LookupResult* result,
10080 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010081 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010082 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010083 case NORMAL:
10084 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010085 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010086 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010087 }
10088 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010089 case FIELD:
10090 value =
10091 JSObject::cast(
10092 result->holder())->FastPropertyAt(result->GetFieldIndex());
10093 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010095 }
10096 return value;
10097 case CONSTANT_FUNCTION:
10098 return result->GetConstantFunction();
10099 case CALLBACKS: {
10100 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010101 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010102 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10103 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010104 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010105 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010106 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 maybe_value = heap->isolate()->pending_exception();
10108 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010109 if (caught_exception != NULL) {
10110 *caught_exception = true;
10111 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010112 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010113 }
10114 return value;
10115 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010116 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010117 }
10118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010119 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010120 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010121 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010122 case CONSTANT_TRANSITION:
10123 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010125 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010126 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010127 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010128 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010129 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010130 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010131}
10132
10133
ager@chromium.org32912102009-01-16 10:38:43 +000010134// Get debugger related details for an object property.
10135// args[0]: object holding property
10136// args[1]: name of the property
10137//
10138// The array returned contains the following information:
10139// 0: Property value
10140// 1: Property details
10141// 2: Property value is exception
10142// 3: Getter function if defined
10143// 4: Setter function if defined
10144// Items 2-4 are only filled if the property has either a getter or a setter
10145// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010146RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010147 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148
10149 ASSERT(args.length() == 2);
10150
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010151 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10152 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010153
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010154 // Make sure to set the current context to the context before the debugger was
10155 // entered (if the debugger is entered). The reason for switching context here
10156 // is that for some property lookups (accessors and interceptors) callbacks
10157 // into the embedding application can occour, and the embedding application
10158 // could have the assumption that its own global context is the current
10159 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010160 SaveContext save(isolate);
10161 if (isolate->debug()->InDebugger()) {
10162 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010163 }
10164
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010165 // Skip the global proxy as it has no properties and always delegates to the
10166 // real global object.
10167 if (obj->IsJSGlobalProxy()) {
10168 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10169 }
10170
10171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 // Check if the name is trivially convertible to an index and get the element
10173 // if so.
10174 uint32_t index;
10175 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010177 Object* element_or_char;
10178 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010179 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010180 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10181 return maybe_element_or_char;
10182 }
10183 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010184 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010185 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010186 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 }
10188
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010189 // Find the number of objects making up this.
10190 int length = LocalPrototypeChainLength(*obj);
10191
10192 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010193 Handle<JSObject> jsproto = obj;
10194 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010195 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010196 jsproto->LocalLookup(*name, &result);
10197 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010198 // LookupResult is not GC safe as it holds raw object pointers.
10199 // GC can happen later in this code so put the required fields into
10200 // local variables using handles when required for later use.
10201 PropertyType result_type = result.type();
10202 Handle<Object> result_callback_obj;
10203 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10205 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010206 }
10207 Smi* property_details = result.GetPropertyDetails().AsSmi();
10208 // DebugLookupResultValue can cause GC so details from LookupResult needs
10209 // to be copied to handles before this.
10210 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010211 Object* raw_value;
10212 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213 DebugLookupResultValue(isolate->heap(), *obj, *name,
10214 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010215 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10216 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010217 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010218
10219 // If the callback object is a fixed array then it contains JavaScript
10220 // getter and/or setter.
10221 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010222 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010223 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010224 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010225 details->set(0, *value);
10226 details->set(1, property_details);
10227 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010228 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010229 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010230 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10231 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010232 }
10233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010235 }
10236 if (i < length - 1) {
10237 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10238 }
10239 }
10240
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010241 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242}
10243
10244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010245RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010246 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010247
10248 ASSERT(args.length() == 2);
10249
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010250 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10251 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010253 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 obj->Lookup(*name, &result);
10255 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010256 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010258 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259}
10260
10261
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262// Return the property type calculated from the property details.
10263// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010264RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010266 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10267 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010268}
10269
10270
10271// Return the property attribute calculated from the property details.
10272// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010273RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010275 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10276 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277}
10278
10279
10280// Return the property insertion index calculated from the property details.
10281// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010282RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010284 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10285 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286}
10287
10288
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289// Return property value from named interceptor.
10290// args[0]: object
10291// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010292RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010293 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010295 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010297 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298
10299 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010300 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301}
10302
10303
10304// Return element value from indexed interceptor.
10305// args[0]: object
10306// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010307RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010310 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10312 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10313
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010314 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315}
10316
10317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010318RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319 ASSERT(args.length() >= 1);
10320 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010321 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 if (isolate->debug()->break_id() == 0 ||
10323 break_id != isolate->debug()->break_id()) {
10324 return isolate->Throw(
10325 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326 }
10327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010328 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329}
10330
10331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010332RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334 ASSERT(args.length() == 1);
10335
10336 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010337 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010338 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10339 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010340 if (!maybe_result->ToObject(&result)) return maybe_result;
10341 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342
10343 // Count all frames which are relevant to debugging stack trace.
10344 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010345 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010346 if (id == StackFrame::NO_ID) {
10347 // If there is no JavaScript stack frame count is 0.
10348 return Smi::FromInt(0);
10349 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010350
10351 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10352 n += it.frame()->GetInlineCount();
10353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354 return Smi::FromInt(n);
10355}
10356
10357
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010358class FrameInspector {
10359 public:
10360 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010361 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010362 Isolate* isolate)
10363 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10364 // Calculate the deoptimized frame.
10365 if (frame->is_optimized()) {
10366 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010367 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010368 }
10369 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010370 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010371 is_optimized_ = frame_->is_optimized();
10372 }
10373
10374 ~FrameInspector() {
10375 // Get rid of the calculated deoptimized frame if any.
10376 if (deoptimized_frame_ != NULL) {
10377 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10378 isolate_);
10379 }
10380 }
10381
10382 int GetParametersCount() {
10383 return is_optimized_
10384 ? deoptimized_frame_->parameters_count()
10385 : frame_->ComputeParametersCount();
10386 }
10387 int expression_count() { return deoptimized_frame_->expression_count(); }
10388 Object* GetFunction() {
10389 return is_optimized_
10390 ? deoptimized_frame_->GetFunction()
10391 : frame_->function();
10392 }
10393 Object* GetParameter(int index) {
10394 return is_optimized_
10395 ? deoptimized_frame_->GetParameter(index)
10396 : frame_->GetParameter(index);
10397 }
10398 Object* GetExpression(int index) {
10399 return is_optimized_
10400 ? deoptimized_frame_->GetExpression(index)
10401 : frame_->GetExpression(index);
10402 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010403 int GetSourcePosition() {
10404 return is_optimized_
10405 ? deoptimized_frame_->GetSourcePosition()
10406 : frame_->LookupCode()->SourcePosition(frame_->pc());
10407 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010408 bool IsConstructor() {
10409 return is_optimized_ && !is_bottommost_
10410 ? deoptimized_frame_->HasConstructStub()
10411 : frame_->IsConstructor();
10412 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010413
10414 // To inspect all the provided arguments the frame might need to be
10415 // replaced with the arguments frame.
10416 void SetArgumentsFrame(JavaScriptFrame* frame) {
10417 ASSERT(has_adapted_arguments_);
10418 frame_ = frame;
10419 is_optimized_ = frame_->is_optimized();
10420 ASSERT(!is_optimized_);
10421 }
10422
10423 private:
10424 JavaScriptFrame* frame_;
10425 DeoptimizedFrameInfo* deoptimized_frame_;
10426 Isolate* isolate_;
10427 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010428 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010429 bool has_adapted_arguments_;
10430
10431 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10432};
10433
10434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435static const int kFrameDetailsFrameIdIndex = 0;
10436static const int kFrameDetailsReceiverIndex = 1;
10437static const int kFrameDetailsFunctionIndex = 2;
10438static const int kFrameDetailsArgumentCountIndex = 3;
10439static const int kFrameDetailsLocalCountIndex = 4;
10440static const int kFrameDetailsSourcePositionIndex = 5;
10441static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010442static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010443static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010444static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010445
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010446
10447static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10448 JavaScriptFrame* frame) {
10449 SaveContext* save = isolate->save_context();
10450 while (save != NULL && !save->IsBelowFrame(frame)) {
10451 save = save->prev();
10452 }
10453 ASSERT(save != NULL);
10454 return save;
10455}
10456
10457
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010458// Return an array with frame details
10459// args[0]: number: break id
10460// args[1]: number: frame index
10461//
10462// The array returned contains the following information:
10463// 0: Frame id
10464// 1: Receiver
10465// 2: Function
10466// 3: Argument count
10467// 4: Local count
10468// 5: Source position
10469// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010470// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010471// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472// Arguments name, value
10473// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010474// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010475RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010476 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477 ASSERT(args.length() == 2);
10478
10479 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010480 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010481 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10482 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010483 if (!maybe_check->ToObject(&check)) return maybe_check;
10484 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010486 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010487
10488 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010489 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010490 if (id == StackFrame::NO_ID) {
10491 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010492 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010493 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010494
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010496 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010498 if (index < count + it.frame()->GetInlineCount()) break;
10499 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010501 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010502
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010503 bool is_optimized = it.frame()->is_optimized();
10504
10505 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10506 if (is_optimized) {
10507 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010508 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010509 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010510 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512 // Traverse the saved contexts chain to find the active context for the
10513 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010514 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515
10516 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010519 // Find source position in unoptimized code.
10520 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521
ulan@chromium.org967e2702012-02-28 09:49:15 +000010522 // Check for constructor frame.
10523 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010525 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010526 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010527 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010528 Handle<ScopeInfo> scope_info(shared->scope_info());
10529 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 // Get the locals names and values into a temporary array.
10532 //
10533 // TODO(1240907): Hide compiler-introduced stack variables
10534 // (e.g. .result)? For users of the debugger, they will probably be
10535 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010536 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010537 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010538
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010539 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010540 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010541 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010542 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010543 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010544 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010545 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010546 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010547 // Get the context containing declarations.
10548 Handle<Context> context(
10549 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010550 for (; i < scope_info->LocalCount(); ++i) {
10551 Handle<String> name(scope_info->LocalName(i));
10552 VariableMode mode;
10553 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010554 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010555 locals->set(i * 2 + 1, context->get(
10556 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 }
10558 }
10559
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010560 // Check whether this frame is positioned at return. If not top
10561 // frame or if the frame is optimized it cannot be at a return.
10562 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010563 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010565 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010566
10567 // If positioned just before return find the value to be returned and add it
10568 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010569 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010570 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010571 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010572 Address internal_frame_sp = NULL;
10573 while (!it2.done()) {
10574 if (it2.frame()->is_internal()) {
10575 internal_frame_sp = it2.frame()->sp();
10576 } else {
10577 if (it2.frame()->is_java_script()) {
10578 if (it2.frame()->id() == it.frame()->id()) {
10579 // The internal frame just before the JavaScript frame contains the
10580 // value to return on top. A debug break at return will create an
10581 // internal frame to store the return value (eax/rax/r0) before
10582 // entering the debug break exit frame.
10583 if (internal_frame_sp != NULL) {
10584 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010585 Handle<Object>(Memory::Object_at(internal_frame_sp),
10586 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010587 break;
10588 }
10589 }
10590 }
10591
10592 // Indicate that the previous frame was not an internal frame.
10593 internal_frame_sp = NULL;
10594 }
10595 it2.Advance();
10596 }
10597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010598
10599 // Now advance to the arguments adapter frame (if any). It contains all
10600 // the provided parameters whereas the function frame always have the number
10601 // of arguments matching the functions parameters. The rest of the
10602 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010603 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010604 it.AdvanceToArgumentsFrame();
10605 frame_inspector.SetArgumentsFrame(it.frame());
10606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607
10608 // Find the number of arguments to fill. At least fill the number of
10609 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010610 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010611 if (argument_count < frame_inspector.GetParametersCount()) {
10612 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613 }
10614
10615 // Calculate the size of the result.
10616 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010617 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010618 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010619 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620
10621 // Add the frame id.
10622 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10623
10624 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010625 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626
10627 // Add the arguments count.
10628 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10629
10630 // Add the locals count
10631 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010632 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010633
10634 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010635 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10637 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010638 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 }
10640
10641 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010642 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010644 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010646
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010647 // Add flags to indicate information on whether this frame is
10648 // bit 0: invoked in the debugger context.
10649 // bit 1: optimized frame.
10650 // bit 2: inlined in optimized frame
10651 int flags = 0;
10652 if (*save->context() == *isolate->debug()->debug_context()) {
10653 flags |= 1 << 0;
10654 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010655 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010656 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010657 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010658 }
10659 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010660
10661 // Fill the dynamic part.
10662 int details_index = kFrameDetailsFirstDynamicIndex;
10663
10664 // Add arguments name and value.
10665 for (int i = 0; i < argument_count; i++) {
10666 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010667 if (i < scope_info->ParameterCount()) {
10668 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671 }
10672
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010673 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010674 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010675 // Get the value from the stack.
10676 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010677 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010678 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 }
10680 }
10681
10682 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010683 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010684 details->set(details_index++, locals->get(i));
10685 }
10686
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010687 // Add the value being returned.
10688 if (at_return) {
10689 details->set(details_index++, *return_value);
10690 }
10691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692 // Add the receiver (same as in function frame).
10693 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10694 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010695 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010696 if (!receiver->IsJSObject() &&
10697 shared->is_classic_mode() &&
10698 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010699 // If the receiver is not a JSObject and the function is not a
10700 // builtin or strict-mode we have hit an optimization where a
10701 // value object is not converted into a wrapped JS objects. To
10702 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703 // by creating correct wrapper object based on the calling frame's
10704 // global context.
10705 it.Advance();
10706 Handle<Context> calling_frames_global_context(
10707 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010708 receiver =
10709 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710 }
10711 details->set(kFrameDetailsReceiverIndex, *receiver);
10712
10713 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010714 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010715}
10716
10717
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010718// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010719static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010720 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010721 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010722 Handle<Context> context,
10723 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010724 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010725 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10726 VariableMode mode;
10727 InitializationFlag init_flag;
10728 int context_index = scope_info->ContextSlotIndex(
10729 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010730
whesse@chromium.org7b260152011-06-20 15:33:18 +000010731 RETURN_IF_EMPTY_HANDLE_VALUE(
10732 isolate,
10733 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010734 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010735 Handle<Object>(context->get(context_index), isolate),
10736 NONE,
10737 kNonStrictMode),
10738 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010739 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010740
10741 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010742}
10743
10744
10745// Create a plain JSObject which materializes the local scope for the specified
10746// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010747static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010748 Isolate* isolate,
10749 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010750 FrameInspector* frame_inspector) {
10751 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010752 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010753 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010754
10755 // Allocate and initialize a JSObject with all the arguments, stack locals
10756 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010757 Handle<JSObject> local_scope =
10758 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010759
10760 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010761 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010762 Handle<Object> value(
10763 i < frame_inspector->GetParametersCount() ?
10764 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10765
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010766 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010768 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010769 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010770 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010771 NONE,
10772 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010773 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010774 }
10775
10776 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010777 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010778 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010780 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010781 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010782 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010783 NONE,
10784 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010785 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010786 }
10787
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010788 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010789 // Third fill all context locals.
10790 Handle<Context> frame_context(Context::cast(frame->context()));
10791 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010792 if (!CopyContextLocalsToScopeObject(
10793 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010794 return Handle<JSObject>();
10795 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010796
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010797 // Finally copy any properties from the function context extension.
10798 // These will be variables introduced by eval.
10799 if (function_context->closure() == *function) {
10800 if (function_context->has_extension() &&
10801 !function_context->IsGlobalContext()) {
10802 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010803 bool threw = false;
10804 Handle<FixedArray> keys =
10805 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10806 if (threw) return Handle<JSObject>();
10807
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010808 for (int i = 0; i < keys->length(); i++) {
10809 // Names of variables introduced by eval are strings.
10810 ASSERT(keys->get(i)->IsString());
10811 Handle<String> key(String::cast(keys->get(i)));
10812 RETURN_IF_EMPTY_HANDLE_VALUE(
10813 isolate,
10814 SetProperty(local_scope,
10815 key,
10816 GetProperty(ext, key),
10817 NONE,
10818 kNonStrictMode),
10819 Handle<JSObject>());
10820 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010821 }
10822 }
10823 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010824
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010825 return local_scope;
10826}
10827
10828
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010829static Handle<JSObject> MaterializeLocalScope(
10830 Isolate* isolate,
10831 JavaScriptFrame* frame,
10832 int inlined_jsframe_index) {
10833 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10834 return MaterializeLocalScopeWithFrameInspector(isolate,
10835 frame,
10836 &frame_inspector);
10837}
10838
10839
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010840// Create a plain JSObject which materializes the closure content for the
10841// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010842static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10843 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010844 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010845
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010846 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010847 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010848
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010849 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010850 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010851 Handle<JSObject> closure_scope =
10852 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010853
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010854 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010855 if (!CopyContextLocalsToScopeObject(
10856 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010857 return Handle<JSObject>();
10858 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010859
10860 // Finally copy any properties from the function context extension. This will
10861 // be variables introduced by eval.
10862 if (context->has_extension()) {
10863 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010864 bool threw = false;
10865 Handle<FixedArray> keys =
10866 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10867 if (threw) return Handle<JSObject>();
10868
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010869 for (int i = 0; i < keys->length(); i++) {
10870 // Names of variables introduced by eval are strings.
10871 ASSERT(keys->get(i)->IsString());
10872 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010873 RETURN_IF_EMPTY_HANDLE_VALUE(
10874 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010875 SetProperty(closure_scope,
10876 key,
10877 GetProperty(ext, key),
10878 NONE,
10879 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010880 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010881 }
10882 }
10883
10884 return closure_scope;
10885}
10886
10887
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010888// Create a plain JSObject which materializes the scope for the specified
10889// catch context.
10890static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10891 Handle<Context> context) {
10892 ASSERT(context->IsCatchContext());
10893 Handle<String> name(String::cast(context->extension()));
10894 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10895 Handle<JSObject> catch_scope =
10896 isolate->factory()->NewJSObject(isolate->object_function());
10897 RETURN_IF_EMPTY_HANDLE_VALUE(
10898 isolate,
10899 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10900 Handle<JSObject>());
10901 return catch_scope;
10902}
10903
10904
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010905// Create a plain JSObject which materializes the block scope for the specified
10906// block context.
10907static Handle<JSObject> MaterializeBlockScope(
10908 Isolate* isolate,
10909 Handle<Context> context) {
10910 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010911 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010912
10913 // Allocate and initialize a JSObject with all the arguments, stack locals
10914 // heap locals and extension properties of the debugged function.
10915 Handle<JSObject> block_scope =
10916 isolate->factory()->NewJSObject(isolate->object_function());
10917
10918 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010919 if (!CopyContextLocalsToScopeObject(
10920 isolate, scope_info, context, block_scope)) {
10921 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010922 }
10923
10924 return block_scope;
10925}
10926
10927
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010928// Create a plain JSObject which materializes the module scope for the specified
10929// module context.
10930static Handle<JSObject> MaterializeModuleScope(
10931 Isolate* isolate,
10932 Handle<Context> context) {
10933 ASSERT(context->IsModuleContext());
10934 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10935
10936 // Allocate and initialize a JSObject with all the members of the debugged
10937 // module.
10938 Handle<JSObject> module_scope =
10939 isolate->factory()->NewJSObject(isolate->object_function());
10940
10941 // Fill all context locals.
10942 if (!CopyContextLocalsToScopeObject(
10943 isolate, scope_info, context, module_scope)) {
10944 return Handle<JSObject>();
10945 }
10946
10947 return module_scope;
10948}
10949
10950
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010951// Iterate over the actual scopes visible from a stack frame. The iteration
10952// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010953// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010954// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010955class ScopeIterator {
10956 public:
10957 enum ScopeType {
10958 ScopeTypeGlobal = 0,
10959 ScopeTypeLocal,
10960 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010961 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010962 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010963 ScopeTypeBlock,
10964 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010965 };
10966
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010967 ScopeIterator(Isolate* isolate,
10968 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010969 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 : isolate_(isolate),
10971 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010972 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010973 function_(JSFunction::cast(frame->function())),
10974 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010975 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010976
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010977 // Catch the case when the debugger stops in an internal function.
10978 Handle<SharedFunctionInfo> shared_info(function_->shared());
10979 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10980 if (shared_info->script() == isolate->heap()->undefined_value()) {
10981 while (context_->closure() == *function_) {
10982 context_ = Handle<Context>(context_->previous(), isolate_);
10983 }
10984 return;
10985 }
10986
10987 // Get the debug info (create it if it does not exist).
10988 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10989 // Return if ensuring debug info failed.
10990 return;
10991 }
10992 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10993
10994 // Find the break point where execution has stopped.
10995 BreakLocationIterator break_location_iterator(debug_info,
10996 ALL_BREAK_LOCATIONS);
10997 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10998 if (break_location_iterator.IsExit()) {
10999 // We are within the return sequence. At the momemt it is not possible to
11000 // get a source position which is consistent with the current scope chain.
11001 // Thus all nested with, catch and block contexts are skipped and we only
11002 // provide the function scope.
11003 if (scope_info->HasContext()) {
11004 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11005 } else {
11006 while (context_->closure() == *function_) {
11007 context_ = Handle<Context>(context_->previous(), isolate_);
11008 }
11009 }
11010 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11011 } else {
11012 // Reparse the code and analyze the scopes.
11013 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11014 Handle<Script> script(Script::cast(shared_info->script()));
11015 Scope* scope = NULL;
11016
11017 // Check whether we are in global, eval or function code.
11018 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11019 if (scope_info->Type() != FUNCTION_SCOPE) {
11020 // Global or eval code.
11021 CompilationInfo info(script);
11022 if (scope_info->Type() == GLOBAL_SCOPE) {
11023 info.MarkAsGlobal();
11024 } else {
11025 ASSERT(scope_info->Type() == EVAL_SCOPE);
11026 info.MarkAsEval();
11027 info.SetCallingContext(Handle<Context>(function_->context()));
11028 }
11029 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11030 scope = info.function()->scope();
11031 }
11032 } else {
11033 // Function code
11034 CompilationInfo info(shared_info);
11035 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11036 scope = info.function()->scope();
11037 }
11038 }
11039
11040 // Retrieve the scope chain for the current position.
11041 if (scope != NULL) {
11042 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11043 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11044 } else {
11045 // A failed reparse indicates that the preparser has diverged from the
11046 // parser or that the preparse data given to the initial parse has been
11047 // faulty. We fail in debug mode but in release mode we only provide the
11048 // information we get from the context chain but nothing about
11049 // completely stack allocated scopes or stack allocated locals.
11050 UNREACHABLE();
11051 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011052 }
11053 }
11054
11055 // More scopes?
11056 bool Done() { return context_.is_null(); }
11057
11058 // Move to the next scope.
11059 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011060 ScopeType scope_type = Type();
11061 if (scope_type == ScopeTypeGlobal) {
11062 // The global scope is always the last in the chain.
11063 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011064 context_ = Handle<Context>();
11065 return;
11066 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011067 if (nested_scope_chain_.is_empty()) {
11068 context_ = Handle<Context>(context_->previous(), isolate_);
11069 } else {
11070 if (nested_scope_chain_.last()->HasContext()) {
11071 ASSERT(context_->previous() != NULL);
11072 context_ = Handle<Context>(context_->previous(), isolate_);
11073 }
11074 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011075 }
11076 }
11077
11078 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011079 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011080 if (!nested_scope_chain_.is_empty()) {
11081 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11082 switch (scope_info->Type()) {
11083 case FUNCTION_SCOPE:
11084 ASSERT(context_->IsFunctionContext() ||
11085 !scope_info->HasContext());
11086 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011087 case MODULE_SCOPE:
11088 ASSERT(context_->IsModuleContext());
11089 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011090 case GLOBAL_SCOPE:
11091 ASSERT(context_->IsGlobalContext());
11092 return ScopeTypeGlobal;
11093 case WITH_SCOPE:
11094 ASSERT(context_->IsWithContext());
11095 return ScopeTypeWith;
11096 case CATCH_SCOPE:
11097 ASSERT(context_->IsCatchContext());
11098 return ScopeTypeCatch;
11099 case BLOCK_SCOPE:
11100 ASSERT(!scope_info->HasContext() ||
11101 context_->IsBlockContext());
11102 return ScopeTypeBlock;
11103 case EVAL_SCOPE:
11104 UNREACHABLE();
11105 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011106 }
11107 if (context_->IsGlobalContext()) {
11108 ASSERT(context_->global()->IsGlobalObject());
11109 return ScopeTypeGlobal;
11110 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011111 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 return ScopeTypeClosure;
11113 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011114 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011115 return ScopeTypeCatch;
11116 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011117 if (context_->IsBlockContext()) {
11118 return ScopeTypeBlock;
11119 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011120 if (context_->IsModuleContext()) {
11121 return ScopeTypeModule;
11122 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011123 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 return ScopeTypeWith;
11125 }
11126
11127 // Return the JavaScript object with the content of the current scope.
11128 Handle<JSObject> ScopeObject() {
11129 switch (Type()) {
11130 case ScopeIterator::ScopeTypeGlobal:
11131 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011132 case ScopeIterator::ScopeTypeLocal:
11133 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011134 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011135 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011136 case ScopeIterator::ScopeTypeWith:
11137 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011138 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11139 case ScopeIterator::ScopeTypeCatch:
11140 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011141 case ScopeIterator::ScopeTypeClosure:
11142 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011143 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011144 case ScopeIterator::ScopeTypeBlock:
11145 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011146 case ScopeIterator::ScopeTypeModule:
11147 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011148 }
11149 UNREACHABLE();
11150 return Handle<JSObject>();
11151 }
11152
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011153 Handle<ScopeInfo> CurrentScopeInfo() {
11154 if (!nested_scope_chain_.is_empty()) {
11155 return nested_scope_chain_.last();
11156 } else if (context_->IsBlockContext()) {
11157 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11158 } else if (context_->IsFunctionContext()) {
11159 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11160 }
11161 return Handle<ScopeInfo>::null();
11162 }
11163
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011164 // Return the context for this scope. For the local context there might not
11165 // be an actual context.
11166 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011167 if (Type() == ScopeTypeGlobal ||
11168 nested_scope_chain_.is_empty()) {
11169 return context_;
11170 } else if (nested_scope_chain_.last()->HasContext()) {
11171 return context_;
11172 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011173 return Handle<Context>();
11174 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011175 }
11176
11177#ifdef DEBUG
11178 // Debug print of the content of the current scope.
11179 void DebugPrint() {
11180 switch (Type()) {
11181 case ScopeIterator::ScopeTypeGlobal:
11182 PrintF("Global:\n");
11183 CurrentContext()->Print();
11184 break;
11185
11186 case ScopeIterator::ScopeTypeLocal: {
11187 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011188 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011189 if (!CurrentContext().is_null()) {
11190 CurrentContext()->Print();
11191 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011192 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 if (extension->IsJSContextExtensionObject()) {
11194 extension->Print();
11195 }
11196 }
11197 }
11198 break;
11199 }
11200
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011201 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011202 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011203 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011204 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011205
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011206 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011207 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011208 CurrentContext()->extension()->Print();
11209 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011210 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011211
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011212 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011213 PrintF("Closure:\n");
11214 CurrentContext()->Print();
11215 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011216 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217 if (extension->IsJSContextExtensionObject()) {
11218 extension->Print();
11219 }
11220 }
11221 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011222
11223 default:
11224 UNREACHABLE();
11225 }
11226 PrintF("\n");
11227 }
11228#endif
11229
11230 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011231 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011232 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011233 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011234 Handle<JSFunction> function_;
11235 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011236 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011237
11238 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11239};
11240
11241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011242RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011244 ASSERT(args.length() == 2);
11245
11246 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011247 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011248 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11249 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011250 if (!maybe_check->ToObject(&check)) return maybe_check;
11251 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011252 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011253
11254 // Get the frame where the debugging is performed.
11255 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011256 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011257 JavaScriptFrame* frame = it.frame();
11258
11259 // Count the visible scopes.
11260 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011261 for (ScopeIterator it(isolate, frame, 0);
11262 !it.Done();
11263 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011264 n++;
11265 }
11266
11267 return Smi::FromInt(n);
11268}
11269
11270
11271static const int kScopeDetailsTypeIndex = 0;
11272static const int kScopeDetailsObjectIndex = 1;
11273static const int kScopeDetailsSize = 2;
11274
11275// Return an array with scope details
11276// args[0]: number: break id
11277// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011278// args[2]: number: inlined frame index
11279// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011280//
11281// The array returned contains the following information:
11282// 0: Scope type
11283// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011284RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011285 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011286 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011287
11288 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011289 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011290 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11291 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011292 if (!maybe_check->ToObject(&check)) return maybe_check;
11293 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011294 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011295 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011296 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011297
11298 // Get the frame where the debugging is performed.
11299 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011300 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011301 JavaScriptFrame* frame = frame_it.frame();
11302
11303 // Find the requested scope.
11304 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011305 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011306 for (; !it.Done() && n < index; it.Next()) {
11307 n++;
11308 }
11309 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011310 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011311 }
11312
11313 // Calculate the size of the result.
11314 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011315 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011316
11317 // Fill in scope details.
11318 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011319 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011320 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011321 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011323 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011324}
11325
11326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011327RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011328 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011329 ASSERT(args.length() == 0);
11330
11331#ifdef DEBUG
11332 // Print the scopes for the top frame.
11333 StackFrameLocator locator;
11334 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011335 for (ScopeIterator it(isolate, frame, 0);
11336 !it.Done();
11337 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011338 it.DebugPrint();
11339 }
11340#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011341 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011342}
11343
11344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011345RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011346 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011347 ASSERT(args.length() == 1);
11348
11349 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011350 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011351 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11352 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011353 if (!maybe_result->ToObject(&result)) return maybe_result;
11354 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011355
11356 // Count all archived V8 threads.
11357 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011358 for (ThreadState* thread =
11359 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011360 thread != NULL;
11361 thread = thread->Next()) {
11362 n++;
11363 }
11364
11365 // Total number of threads is current thread and archived threads.
11366 return Smi::FromInt(n + 1);
11367}
11368
11369
11370static const int kThreadDetailsCurrentThreadIndex = 0;
11371static const int kThreadDetailsThreadIdIndex = 1;
11372static const int kThreadDetailsSize = 2;
11373
11374// Return an array with thread details
11375// args[0]: number: break id
11376// args[1]: number: thread index
11377//
11378// The array returned contains the following information:
11379// 0: Is current thread?
11380// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011381RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011382 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011383 ASSERT(args.length() == 2);
11384
11385 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011386 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011387 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11388 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011389 if (!maybe_check->ToObject(&check)) return maybe_check;
11390 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011391 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11392
11393 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 Handle<FixedArray> details =
11395 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011396
11397 // Thread index 0 is current thread.
11398 if (index == 0) {
11399 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011400 details->set(kThreadDetailsCurrentThreadIndex,
11401 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011402 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011403 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011404 } else {
11405 // Find the thread with the requested index.
11406 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011407 ThreadState* thread =
11408 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011409 while (index != n && thread != NULL) {
11410 thread = thread->Next();
11411 n++;
11412 }
11413 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011414 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011415 }
11416
11417 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011418 details->set(kThreadDetailsCurrentThreadIndex,
11419 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011420 details->set(kThreadDetailsThreadIdIndex,
11421 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011422 }
11423
11424 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011425 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011426}
11427
11428
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011429// Sets the disable break state
11430// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011431RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011432 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011433 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011434 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011435 isolate->debug()->set_disable_break(disable_break);
11436 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011437}
11438
11439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011440RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011441 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011442 ASSERT(args.length() == 1);
11443
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011444 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011445 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011446 // Find the number of break points
11447 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011448 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011449 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011450 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011451 Handle<FixedArray>::cast(break_locations));
11452}
11453
11454
11455// Set a break point in a function
11456// args[0]: function
11457// args[1]: number: break source position (within the function source)
11458// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011459RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011460 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011461 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011462 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011463 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011464 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11465 RUNTIME_ASSERT(source_position >= 0);
11466 Handle<Object> break_point_object_arg = args.at<Object>(2);
11467
11468 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011469 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11470 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011471
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011472 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011473}
11474
11475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011476Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11477 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011478 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011479 // Iterate the heap looking for SharedFunctionInfo generated from the
11480 // script. The inner most SharedFunctionInfo containing the source position
11481 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011482 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011483 // which is found is not compiled it is compiled and the heap is iterated
11484 // again as the compilation might create inner functions from the newly
11485 // compiled function and the actual requested break point might be in one of
11486 // these functions.
11487 bool done = false;
11488 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011489 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011490 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011491 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011492 { // Extra scope for iterator and no-allocation.
11493 isolate->heap()->EnsureHeapIsIterable();
11494 AssertNoAllocation no_alloc_during_heap_iteration;
11495 HeapIterator iterator;
11496 for (HeapObject* obj = iterator.next();
11497 obj != NULL; obj = iterator.next()) {
11498 if (obj->IsSharedFunctionInfo()) {
11499 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11500 if (shared->script() == *script) {
11501 // If the SharedFunctionInfo found has the requested script data and
11502 // contains the source position it is a candidate.
11503 int start_position = shared->function_token_position();
11504 if (start_position == RelocInfo::kNoPosition) {
11505 start_position = shared->start_position();
11506 }
11507 if (start_position <= position &&
11508 position <= shared->end_position()) {
11509 // If there is no candidate or this function is within the current
11510 // candidate this is the new candidate.
11511 if (target.is_null()) {
11512 target_start_position = start_position;
11513 target = shared;
11514 } else {
11515 if (target_start_position == start_position &&
11516 shared->end_position() == target->end_position()) {
11517 // If a top-level function contain only one function
11518 // declartion the source for the top-level and the
11519 // function is the same. In that case prefer the non
11520 // top-level function.
11521 if (!shared->is_toplevel()) {
11522 target_start_position = start_position;
11523 target = shared;
11524 }
11525 } else if (target_start_position <= start_position &&
11526 shared->end_position() <= target->end_position()) {
11527 // This containment check includes equality as a function
11528 // inside a top-level function can share either start or end
11529 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011530 target_start_position = start_position;
11531 target = shared;
11532 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011533 }
11534 }
11535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011536 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011537 } // End for loop.
11538 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542 }
11543
11544 // If the candidate found is compiled we are done. NOTE: when lazy
11545 // compilation of inner functions is introduced some additional checking
11546 // needs to be done here to compile inner functions.
11547 done = target->is_compiled();
11548 if (!done) {
11549 // If the candidate is not compiled compile it to reveal any inner
11550 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011551 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011552 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011553 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011554
11555 return *target;
11556}
11557
11558
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011559// Changes the state of a break point in a script and returns source position
11560// where break point was set. NOTE: Regarding performance see the NOTE for
11561// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011562// args[0]: script to set break point in
11563// args[1]: number: break source position (within the script source)
11564// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011565RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011567 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011568 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011569 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11570 RUNTIME_ASSERT(source_position >= 0);
11571 Handle<Object> break_point_object_arg = args.at<Object>(2);
11572
11573 // Get the script from the script wrapper.
11574 RUNTIME_ASSERT(wrapper->value()->IsScript());
11575 Handle<Script> script(Script::cast(wrapper->value()));
11576
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011577 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011579 if (!result->IsUndefined()) {
11580 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11581 // Find position within function. The script position might be before the
11582 // source position of the first function.
11583 int position;
11584 if (shared->start_position() > source_position) {
11585 position = 0;
11586 } else {
11587 position = source_position - shared->start_position();
11588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011589 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011590 position += shared->start_position();
11591 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011592 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011594}
11595
11596
11597// Clear a break point
11598// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011599RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011600 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601 ASSERT(args.length() == 1);
11602 Handle<Object> break_point_object_arg = args.at<Object>(0);
11603
11604 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011606
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011607 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011608}
11609
11610
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011611// Change the state of break on exceptions.
11612// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11613// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011614RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011616 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011617 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011618 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011619
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011620 // If the number doesn't match an enum value, the ChangeBreakOnException
11621 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011622 ExceptionBreakType type =
11623 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011624 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 isolate->debug()->ChangeBreakOnException(type, enable);
11626 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627}
11628
11629
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011630// Returns the state of break on exceptions
11631// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011632RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011634 ASSERT(args.length() == 1);
11635 RUNTIME_ASSERT(args[0]->IsNumber());
11636
11637 ExceptionBreakType type =
11638 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011640 return Smi::FromInt(result);
11641}
11642
11643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011644// Prepare for stepping
11645// args[0]: break id for checking execution state
11646// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011647// args[2]: number of times to perform the step, for step out it is the number
11648// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011649RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011651 ASSERT(args.length() == 3);
11652 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011653 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011654 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11655 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011656 if (!maybe_check->ToObject(&check)) return maybe_check;
11657 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011660 }
11661
11662 // Get the step action and check validity.
11663 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11664 if (step_action != StepIn &&
11665 step_action != StepNext &&
11666 step_action != StepOut &&
11667 step_action != StepInMin &&
11668 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011670 }
11671
11672 // Get the number of steps.
11673 int step_count = NumberToInt32(args[2]);
11674 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011676 }
11677
ager@chromium.orga1645e22009-09-09 19:27:10 +000011678 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011679 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011680
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011682 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11683 step_count);
11684 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011685}
11686
11687
11688// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011689RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011691 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011692 isolate->debug()->ClearStepping();
11693 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011694}
11695
11696
11697// Creates a copy of the with context chain. The copy of the context chain is
11698// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011699static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11700 Handle<JSFunction> function,
11701 Handle<Context> base,
11702 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011703 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011704 HandleScope scope(isolate);
11705 List<Handle<ScopeInfo> > scope_chain;
11706 List<Handle<Context> > context_chain;
11707
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011708 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011709 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11710 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11711 ASSERT(!it.Done());
11712 scope_chain.Add(it.CurrentScopeInfo());
11713 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011714 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011715
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011716 // At the end of the chain. Return the base context to link to.
11717 Handle<Context> context = base;
11718
11719 // Iteratively copy and or materialize the nested contexts.
11720 while (!scope_chain.is_empty()) {
11721 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11722 Handle<Context> current = context_chain.RemoveLast();
11723 ASSERT(!(scope_info->HasContext() & current.is_null()));
11724
11725 if (scope_info->Type() == CATCH_SCOPE) {
11726 Handle<String> name(String::cast(current->extension()));
11727 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11728 context =
11729 isolate->factory()->NewCatchContext(function,
11730 context,
11731 name,
11732 thrown_object);
11733 } else if (scope_info->Type() == BLOCK_SCOPE) {
11734 // Materialize the contents of the block scope into a JSObject.
11735 Handle<JSObject> block_scope_object =
11736 MaterializeBlockScope(isolate, current);
11737 if (block_scope_object.is_null()) {
11738 return Handle<Context>::null();
11739 }
11740 // Allocate a new function context for the debug evaluation and set the
11741 // extension object.
11742 Handle<Context> new_context =
11743 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11744 function);
11745 new_context->set_extension(*block_scope_object);
11746 new_context->set_previous(*context);
11747 context = new_context;
11748 } else {
11749 ASSERT(scope_info->Type() == WITH_SCOPE);
11750 ASSERT(current->IsWithContext());
11751 Handle<JSObject> extension(JSObject::cast(current->extension()));
11752 context =
11753 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011754 }
erikcorry0ad885c2011-11-21 13:51:57 +000011755 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011756
11757 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011758}
11759
11760
11761// Helper function to find or create the arguments object for
11762// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011763static Handle<Object> GetArgumentsObject(Isolate* isolate,
11764 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011765 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011766 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011767 Handle<Context> function_context) {
11768 // Try to find the value of 'arguments' to pass as parameter. If it is not
11769 // found (that is the debugged function does not reference 'arguments' and
11770 // does not support eval) then create an 'arguments' object.
11771 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011772 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011775 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011776 }
11777 }
11778
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011779 if (scope_info->HasHeapAllocatedLocals()) {
11780 VariableMode mode;
11781 InitializationFlag init_flag;
11782 index = scope_info->ContextSlotIndex(
11783 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011785 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011786 }
11787 }
11788
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011789 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11790 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011791 Handle<JSObject> arguments =
11792 isolate->factory()->NewArgumentsObject(function, length);
11793 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011794
11795 AssertNoAllocation no_gc;
11796 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011798 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011800 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801 return arguments;
11802}
11803
11804
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011805static const char kSourceStr[] =
11806 "(function(arguments,__source__){return eval(__source__);})";
11807
11808
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011809// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011810// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811// extension part has all the parameters and locals of the function on the
11812// stack frame. A function which calls eval with the code to evaluate is then
11813// compiled in this context and called in this context. As this context
11814// replaces the context of the function on the stack frame a new (empty)
11815// function is created as well to be used as the closure for the context.
11816// This function and the context acts as replacements for the function on the
11817// stack frame presenting the same view of the values of parameters and
11818// local variables as if the piece of JavaScript was evaluated at the point
11819// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011820RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011821 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011822
11823 // Check the execution state and decode arguments frame and source to be
11824 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011825 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011826 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011827 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11828 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011829 if (!maybe_check_result->ToObject(&check_result)) {
11830 return maybe_check_result;
11831 }
11832 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011833 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011834 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011835 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11836 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011837 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011838
11839 // Handle the processing of break.
11840 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841
11842 // Get the frame where the debugging is performed.
11843 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011844 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011845 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011846 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11847 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011848 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849
11850 // Traverse the saved contexts chain to find the active context for the
11851 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011852 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011854 SaveContext savex(isolate);
11855 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011856
11857 // Create the (empty) function replacing the function on the stack frame for
11858 // the purpose of evaluating in the context created below. It is important
11859 // that this function does not describe any parameters and local variables
11860 // in the context. If it does then this will cause problems with the lookup
11861 // in Context::Lookup, where context slots for parameters and local variables
11862 // are looked at before the extension object.
11863 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11865 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 go_between->set_context(function->context());
11867#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011868 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11869 ASSERT(go_between_scope_info->ParameterCount() == 0);
11870 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871#endif
11872
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011873 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011874 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11875 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877
11878 // Allocate a new context for the debug evaluation and set the extension
11879 // object build.
11880 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11882 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011883 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011885 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011886 Handle<Context> function_context;
11887 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011888 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011889 function_context = Handle<Context>(frame_context->declaration_context());
11890 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011891 context = CopyNestedScopeContextChain(isolate,
11892 go_between,
11893 context,
11894 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011895 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011897 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011898 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011899 context =
11900 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011901 }
11902
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011903 // Wrap the evaluation statement in a new function compiled in the newly
11904 // created context. The function has one parameter which has to be called
11905 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011906 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011908
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011909 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910 isolate->factory()->NewStringFromAscii(
11911 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011912
11913 // Currently, the eval code will be executed in non-strict mode,
11914 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011915 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011916 Compiler::CompileEval(function_source,
11917 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011918 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011919 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011920 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011921 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011922 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924
11925 // Invoke the result of the compilation to get the evaluation function.
11926 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011927 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 Handle<Object> evaluation_function =
11929 Execution::Call(compiled_function, receiver, 0, NULL,
11930 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011931 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011932
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011933 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011934 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011935 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011936 scope_info,
11937 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011938
11939 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011940 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011941 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011942 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11943 receiver,
11944 ARRAY_SIZE(argv),
11945 argv,
11946 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011947 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011948
11949 // Skip the global proxy as it has no properties and always delegates to the
11950 // real global object.
11951 if (result->IsJSGlobalProxy()) {
11952 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11953 }
11954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011955 return *result;
11956}
11957
11958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011959RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961
11962 // Check the execution state and decode arguments frame and source to be
11963 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011964 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011965 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011966 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11967 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011968 if (!maybe_check_result->ToObject(&check_result)) {
11969 return maybe_check_result;
11970 }
11971 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011972 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11973 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011974 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011975
11976 // Handle the processing of break.
11977 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978
11979 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011980 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011981 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011982 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011983 top = top->prev();
11984 }
11985 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011986 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011987 }
11988
11989 // Get the global context now set to the top context from before the
11990 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011991 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011992
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011993 bool is_global = true;
11994
11995 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011996 // Create a new with context with the additional context information between
11997 // the context of the debugged function and the eval code to be executed.
11998 context = isolate->factory()->NewWithContext(
11999 Handle<JSFunction>(context->closure()),
12000 context,
12001 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012002 is_global = false;
12003 }
12004
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012006 // Currently, the eval code will be executed in non-strict mode,
12007 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012008 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012009 Compiler::CompileEval(source,
12010 context,
12011 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012012 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012013 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012014 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012016 Handle<JSFunction>(
12017 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12018 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012019
12020 // Invoke the result of the compilation to get the evaluation function.
12021 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012022 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012023 Handle<Object> result =
12024 Execution::Call(compiled_function, receiver, 0, NULL,
12025 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012026 // Clear the oneshot breakpoints so that the debugger does not step further.
12027 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012028 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012029 return *result;
12030}
12031
12032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012033RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012035 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012036
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012037 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012038 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012039
12040 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012041 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012042 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12043 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12044 // because using
12045 // instances->set(i, *GetScriptWrapper(script))
12046 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012047 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012048 Handle<JSValue> wrapper = GetScriptWrapper(script);
12049 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050 }
12051
12052 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012053 Handle<JSObject> result =
12054 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012055 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012056 return *result;
12057}
12058
12059
12060// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012061static int DebugReferencedBy(HeapIterator* iterator,
12062 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063 Object* instance_filter, int max_references,
12064 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012065 JSFunction* arguments_function) {
12066 NoHandleAllocation ha;
12067 AssertNoAllocation no_alloc;
12068
12069 // Iterate the heap.
12070 int count = 0;
12071 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012072 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012073 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074 (max_references == 0 || count < max_references)) {
12075 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 if (heap_obj->IsJSObject()) {
12077 // Skip context extension objects and argument arrays as these are
12078 // checked in the context of functions using them.
12079 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012080 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012081 obj->map()->constructor() == arguments_function) {
12082 continue;
12083 }
12084
12085 // Check if the JS object has a reference to the object looked for.
12086 if (obj->ReferencesObject(target)) {
12087 // Check instance filter if supplied. This is normally used to avoid
12088 // references from mirror objects (see Runtime_IsInPrototypeChain).
12089 if (!instance_filter->IsUndefined()) {
12090 Object* V = obj;
12091 while (true) {
12092 Object* prototype = V->GetPrototype();
12093 if (prototype->IsNull()) {
12094 break;
12095 }
12096 if (instance_filter == prototype) {
12097 obj = NULL; // Don't add this object.
12098 break;
12099 }
12100 V = prototype;
12101 }
12102 }
12103
12104 if (obj != NULL) {
12105 // Valid reference found add to instance array if supplied an update
12106 // count.
12107 if (instances != NULL && count < instances_size) {
12108 instances->set(count, obj);
12109 }
12110 last = obj;
12111 count++;
12112 }
12113 }
12114 }
12115 }
12116
12117 // Check for circular reference only. This can happen when the object is only
12118 // referenced from mirrors and has a circular reference in which case the
12119 // object is not really alive and would have been garbage collected if not
12120 // referenced from the mirror.
12121 if (count == 1 && last == target) {
12122 count = 0;
12123 }
12124
12125 // Return the number of referencing objects found.
12126 return count;
12127}
12128
12129
12130// Scan the heap for objects with direct references to an object
12131// args[0]: the object to find references to
12132// args[1]: constructor function for instances to exclude (Mirror)
12133// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012134RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012135 ASSERT(args.length() == 3);
12136
12137 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012138 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12139 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012140 // The heap iterator reserves the right to do a GC to make the heap iterable.
12141 // Due to the GC above we know it won't need to do that, but it seems cleaner
12142 // to get the heap iterator constructed before we start having unprotected
12143 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144
12145 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012146 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012147 Object* instance_filter = args[1];
12148 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12149 instance_filter->IsJSObject());
12150 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12151 RUNTIME_ASSERT(max_references >= 0);
12152
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012155 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157 JSFunction* arguments_function =
12158 JSFunction::cast(arguments_boilerplate->map()->constructor());
12159
12160 // Get the number of referencing objects.
12161 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012162 HeapIterator heap_iterator;
12163 count = DebugReferencedBy(&heap_iterator,
12164 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012165 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166
12167 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012168 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012169 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012170 if (!maybe_object->ToObject(&object)) return maybe_object;
12171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012172 FixedArray* instances = FixedArray::cast(object);
12173
12174 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012175 // AllocateFixedArray above does not make the heap non-iterable.
12176 ASSERT(HEAP->IsHeapIterable());
12177 HeapIterator heap_iterator2;
12178 count = DebugReferencedBy(&heap_iterator2,
12179 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012180 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012181
12182 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012183 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012184 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012185 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012186 if (!maybe_result->ToObject(&result)) return maybe_result;
12187 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188}
12189
12190
12191// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012192static int DebugConstructedBy(HeapIterator* iterator,
12193 JSFunction* constructor,
12194 int max_references,
12195 FixedArray* instances,
12196 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012197 AssertNoAllocation no_alloc;
12198
12199 // Iterate the heap.
12200 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012201 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012202 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203 (max_references == 0 || count < max_references)) {
12204 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205 if (heap_obj->IsJSObject()) {
12206 JSObject* obj = JSObject::cast(heap_obj);
12207 if (obj->map()->constructor() == constructor) {
12208 // Valid reference found add to instance array if supplied an update
12209 // count.
12210 if (instances != NULL && count < instances_size) {
12211 instances->set(count, obj);
12212 }
12213 count++;
12214 }
12215 }
12216 }
12217
12218 // Return the number of referencing objects found.
12219 return count;
12220}
12221
12222
12223// Scan the heap for objects constructed by a specific function.
12224// args[0]: the constructor to find instances of
12225// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012226RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227 ASSERT(args.length() == 2);
12228
12229 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012230 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12231 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232
12233 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012234 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12236 RUNTIME_ASSERT(max_references >= 0);
12237
12238 // Get the number of referencing objects.
12239 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012240 HeapIterator heap_iterator;
12241 count = DebugConstructedBy(&heap_iterator,
12242 constructor,
12243 max_references,
12244 NULL,
12245 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012246
12247 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012248 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012249 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012250 if (!maybe_object->ToObject(&object)) return maybe_object;
12251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012252 FixedArray* instances = FixedArray::cast(object);
12253
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012254 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012255 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012256 HeapIterator heap_iterator2;
12257 count = DebugConstructedBy(&heap_iterator2,
12258 constructor,
12259 max_references,
12260 instances,
12261 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262
12263 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012264 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012265 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12266 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012267 if (!maybe_result->ToObject(&result)) return maybe_result;
12268 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012269 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012270}
12271
12272
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012273// Find the effective prototype object as returned by __proto__.
12274// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012275RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012276 ASSERT(args.length() == 1);
12277
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012278 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012279
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012280 // Use the __proto__ accessor.
12281 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282}
12283
12284
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012285// Patches script source (should be called upon BeforeCompile event).
12286RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12287 HandleScope scope(isolate);
12288 ASSERT(args.length() == 2);
12289
12290 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12291 Handle<String> source(String::cast(args[1]));
12292
12293 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12294 Handle<Script> script(Script::cast(script_wrapper->value()));
12295
12296 int compilation_state = Smi::cast(script->compilation_state())->value();
12297 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12298 script->set_source(*source);
12299
12300 return isolate->heap()->undefined_value();
12301}
12302
12303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012304RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012305 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012307 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012308}
12309
12310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012311RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012312#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012313 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012314 ASSERT(args.length() == 1);
12315 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012316 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012317 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012318 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012319 return Failure::Exception();
12320 }
12321 func->code()->PrintLn();
12322#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012323 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012324}
ager@chromium.org9085a012009-05-11 19:22:57 +000012325
12326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012327RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012328#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012329 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012330 ASSERT(args.length() == 1);
12331 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012332 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012333 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012334 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012335 return Failure::Exception();
12336 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012337 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012338#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012339 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012340}
12341
12342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012343RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012344 NoHandleAllocation ha;
12345 ASSERT(args.length() == 1);
12346
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012347 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012348 return f->shared()->inferred_name();
12349}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012350
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012351
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012352static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12353 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012354 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012355 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012356 int counter = 0;
12357 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012358 for (HeapObject* obj = iterator->next();
12359 obj != NULL;
12360 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012361 ASSERT(obj != NULL);
12362 if (!obj->IsSharedFunctionInfo()) {
12363 continue;
12364 }
12365 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12366 if (shared->script() != script) {
12367 continue;
12368 }
12369 if (counter < buffer_size) {
12370 buffer->set(counter, shared);
12371 }
12372 counter++;
12373 }
12374 return counter;
12375}
12376
12377// For a script finds all SharedFunctionInfo's in the heap that points
12378// to this script. Returns JSArray of SharedFunctionInfo wrapped
12379// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012380RUNTIME_FUNCTION(MaybeObject*,
12381 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012382 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012383 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012384 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012385
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012386
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012387 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12388
12389 const int kBufferSize = 32;
12390
12391 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012392 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012393 int number;
12394 {
12395 isolate->heap()->EnsureHeapIsIterable();
12396 AssertNoAllocation no_allocations;
12397 HeapIterator heap_iterator;
12398 Script* scr = *script;
12399 FixedArray* arr = *array;
12400 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12401 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012402 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012403 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012404 isolate->heap()->EnsureHeapIsIterable();
12405 AssertNoAllocation no_allocations;
12406 HeapIterator heap_iterator;
12407 Script* scr = *script;
12408 FixedArray* arr = *array;
12409 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012410 }
12411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012412 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012413 result->set_length(Smi::FromInt(number));
12414
12415 LiveEdit::WrapSharedFunctionInfos(result);
12416
12417 return *result;
12418}
12419
12420// For a script calculates compilation information about all its functions.
12421// The script source is explicitly specified by the second argument.
12422// The source of the actual script is not used, however it is important that
12423// all generated code keeps references to this particular instance of script.
12424// Returns a JSArray of compilation infos. The array is ordered so that
12425// each function with all its descendant is always stored in a continues range
12426// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012427RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012428 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012429 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012430 CONVERT_ARG_CHECKED(JSValue, script, 0);
12431 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012432 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12433
12434 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12435
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012436 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012437 return Failure::Exception();
12438 }
12439
12440 return result;
12441}
12442
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012443// Changes the source of the script to a new_source.
12444// If old_script_name is provided (i.e. is a String), also creates a copy of
12445// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012446RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012447 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012448 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012449 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12450 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012452
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012453 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12454 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012455
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012456 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12457 new_source,
12458 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012459
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012460 if (old_script->IsScript()) {
12461 Handle<Script> script_handle(Script::cast(old_script));
12462 return *(GetScriptWrapper(script_handle));
12463 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012464 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012465 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012466}
12467
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012469RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012470 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012471 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012472 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012473 return LiveEdit::FunctionSourceUpdated(shared_info);
12474}
12475
12476
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012477// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012478RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012479 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012481 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12482 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012483
ager@chromium.orgac091b72010-05-05 07:34:42 +000012484 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012485}
12486
12487// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012488RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012489 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012490 HandleScope scope(isolate);
12491 Handle<Object> function_object(args[0], isolate);
12492 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012493
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012494 if (function_object->IsJSValue()) {
12495 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12496 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012497 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12498 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012499 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012500 }
12501
12502 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12503 } else {
12504 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12505 // and we check it in this function.
12506 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012508 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012509}
12510
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012511
12512// In a code of a parent function replaces original function as embedded object
12513// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012514RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012515 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012516 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012517
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012518 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12519 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12520 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012521
12522 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12523 subst_wrapper);
12524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012525 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012526}
12527
12528
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012529// Updates positions of a shared function info (first parameter) according
12530// to script source change. Text change is described in second parameter as
12531// array of groups of 3 numbers:
12532// (change_begin, change_end, change_end_new_position).
12533// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012534RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012535 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012536 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012537 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12538 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012539
ager@chromium.orgac091b72010-05-05 07:34:42 +000012540 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012541}
12542
12543
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012544// For array of SharedFunctionInfo's (each wrapped in JSValue)
12545// checks that none of them have activations on stacks (of any thread).
12546// Returns array of the same length with corresponding results of
12547// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012548RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012549 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012550 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012551 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12552 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012553
ager@chromium.org357bf652010-04-12 11:30:10 +000012554 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012555}
12556
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012557// Compares 2 strings line-by-line, then token-wise and returns diff in form
12558// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12559// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012560RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012561 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012562 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012563 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12564 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012565
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012566 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012567}
12568
12569
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012570// A testing entry. Returns statement position which is the closest to
12571// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012572RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012573 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012574 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012575 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012576 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12577
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012579
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012580 if (code->kind() != Code::FUNCTION &&
12581 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012582 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012583 }
12584
12585 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012586 int closest_pc = 0;
12587 int distance = kMaxInt;
12588 while (!it.done()) {
12589 int statement_position = static_cast<int>(it.rinfo()->data());
12590 // Check if this break point is closer that what was previously found.
12591 if (source_position <= statement_position &&
12592 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012593 closest_pc =
12594 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012595 distance = statement_position - source_position;
12596 // Check whether we can't get any closer.
12597 if (distance == 0) break;
12598 }
12599 it.next();
12600 }
12601
12602 return Smi::FromInt(closest_pc);
12603}
12604
12605
ager@chromium.org357bf652010-04-12 11:30:10 +000012606// Calls specified function with or without entering the debugger.
12607// This is used in unit tests to run code as if debugger is entered or simply
12608// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012609RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012610 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012611 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012612 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12613 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012614
12615 Handle<Object> result;
12616 bool pending_exception;
12617 {
12618 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012619 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012620 &pending_exception);
12621 } else {
12622 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012623 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012624 &pending_exception);
12625 }
12626 }
12627 if (!pending_exception) {
12628 return *result;
12629 } else {
12630 return Failure::Exception();
12631 }
12632}
12633
12634
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012635// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012636RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012637 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012638 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012639 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12640 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012641 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012642}
12643
12644
12645// Performs a GC.
12646// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012647RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012648 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012649 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012650}
12651
12652
12653// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012654RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012655 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012656 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012657 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012658 }
12659 return Smi::FromInt(usage);
12660}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012661
12662
12663// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012664RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012665#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012666 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012667#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012668 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012669#endif
12670}
12671
12672
12673// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012674RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012675#ifdef LIVE_OBJECT_LIST
12676 return LiveObjectList::Capture();
12677#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012678 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012679#endif
12680}
12681
12682
12683// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012684RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012685#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012686 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012687 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012688 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012689#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012690 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012691#endif
12692}
12693
12694
12695// Generates the response to a debugger request for a dump of the objects
12696// contained in the difference between the captured live object lists
12697// specified by id1 and id2.
12698// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12699// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012700RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012701#ifdef LIVE_OBJECT_LIST
12702 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012703 CONVERT_SMI_ARG_CHECKED(id1, 0);
12704 CONVERT_SMI_ARG_CHECKED(id2, 1);
12705 CONVERT_SMI_ARG_CHECKED(start, 2);
12706 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012707 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012708 EnterDebugger enter_debugger;
12709 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12710#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012711 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012712#endif
12713}
12714
12715
12716// Gets the specified object as requested by the debugger.
12717// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012718RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012719#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012720 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012721 Object* result = LiveObjectList::GetObj(obj_id);
12722 return result;
12723#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012724 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012725#endif
12726}
12727
12728
12729// Gets the obj id for the specified address if valid.
12730// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012731RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012732#ifdef LIVE_OBJECT_LIST
12733 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012734 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012735 Object* result = LiveObjectList::GetObjId(address);
12736 return result;
12737#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012738 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012739#endif
12740}
12741
12742
12743// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012744RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012745#ifdef LIVE_OBJECT_LIST
12746 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012747 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012748 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12749 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12750 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12751 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012752 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012753
12754 Handle<JSObject> instance_filter;
12755 if (args[1]->IsJSObject()) {
12756 instance_filter = args.at<JSObject>(1);
12757 }
12758 bool verbose = false;
12759 if (args[2]->IsBoolean()) {
12760 verbose = args[2]->IsTrue();
12761 }
12762 int start = 0;
12763 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012764 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012765 }
12766 int limit = Smi::kMaxValue;
12767 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012768 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012769 }
12770
12771 return LiveObjectList::GetObjRetainers(obj_id,
12772 instance_filter,
12773 verbose,
12774 start,
12775 limit,
12776 filter_obj);
12777#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012778 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012779#endif
12780}
12781
12782
12783// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012784RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012785#ifdef LIVE_OBJECT_LIST
12786 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012787 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12788 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012789 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12790
12791 Handle<JSObject> instance_filter;
12792 if (args[2]->IsJSObject()) {
12793 instance_filter = args.at<JSObject>(2);
12794 }
12795
12796 Object* result =
12797 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12798 return result;
12799#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012800 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012801#endif
12802}
12803
12804
12805// Generates the response to a debugger request for a list of all
12806// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012807RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012808#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012809 CONVERT_SMI_ARG_CHECKED(start, 0);
12810 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012811 return LiveObjectList::Info(start, count);
12812#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012813 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012814#endif
12815}
12816
12817
12818// Gets a dump of the specified object as requested by the debugger.
12819// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012821#ifdef LIVE_OBJECT_LIST
12822 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012823 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012824 Object* result = LiveObjectList::PrintObj(obj_id);
12825 return result;
12826#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012827 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012828#endif
12829}
12830
12831
12832// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012833RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012834#ifdef LIVE_OBJECT_LIST
12835 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012836 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012837#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012838 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012839#endif
12840}
12841
12842
12843// Generates the response to a debugger request for a summary of the types
12844// of objects in the difference between the captured live object lists
12845// specified by id1 and id2.
12846// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12847// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012848RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012849#ifdef LIVE_OBJECT_LIST
12850 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012851 CONVERT_SMI_ARG_CHECKED(id1, 0);
12852 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012853 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012854
12855 EnterDebugger enter_debugger;
12856 return LiveObjectList::Summarize(id1, id2, filter_obj);
12857#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012858 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012859#endif
12860}
12861
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012862#endif // ENABLE_DEBUGGER_SUPPORT
12863
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012865RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012866 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012867 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012868 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012869}
12870
12871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012872RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012873 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012874 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012875 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012876}
12877
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012879// Finds the script object from the script data. NOTE: This operation uses
12880// heap traversal to find the function generated for the source position
12881// for the requested break point. For lazily compiled functions several heap
12882// traversals might be required rendering this operation as a rather slow
12883// operation. However for setting break points which is normally done through
12884// some kind of user interaction the performance is not crucial.
12885static Handle<Object> Runtime_GetScriptFromScriptName(
12886 Handle<String> script_name) {
12887 // Scan the heap for Script objects to find the script with the requested
12888 // script data.
12889 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012890 script_name->GetHeap()->EnsureHeapIsIterable();
12891 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012892 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012893 HeapObject* obj = NULL;
12894 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012895 // If a script is found check if it has the script data requested.
12896 if (obj->IsScript()) {
12897 if (Script::cast(obj)->name()->IsString()) {
12898 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12899 script = Handle<Script>(Script::cast(obj));
12900 }
12901 }
12902 }
12903 }
12904
12905 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012906 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012907
12908 // Return the script found.
12909 return GetScriptWrapper(script);
12910}
12911
12912
12913// Get the script object from script data. NOTE: Regarding performance
12914// see the NOTE for GetScriptFromScriptData.
12915// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012916RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012917 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012918
12919 ASSERT(args.length() == 1);
12920
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012921 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012922
12923 // Find the requested script.
12924 Handle<Object> result =
12925 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12926 return *result;
12927}
12928
12929
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012930// Determines whether the given stack frame should be displayed in
12931// a stack trace. The caller is the error constructor that asked
12932// for the stack trace to be collected. The first time a construct
12933// call to this function is encountered it is skipped. The seen_caller
12934// in/out parameter is used to remember if the caller has been seen
12935// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012936static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12937 Object* caller,
12938 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012939 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012940 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012941 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012942 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012943 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12944 Object* raw_fun = frame->function();
12945 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012946 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012947 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012948 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012949 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012950 *seen_caller = true;
12951 return false;
12952 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012953 // Skip all frames until we've seen the caller.
12954 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012955 // Also, skip non-visible built-in functions and any call with the builtins
12956 // object as receiver, so as to not reveal either the builtins object or
12957 // an internal function.
12958 // The --builtins-in-stack-traces command line flag allows including
12959 // internal call sites in the stack trace for debugging purposes.
12960 if (!FLAG_builtins_in_stack_traces) {
12961 JSFunction* fun = JSFunction::cast(raw_fun);
12962 if (frame->receiver()->IsJSBuiltinsObject() ||
12963 (fun->IsBuiltin() && !fun->shared()->native())) {
12964 return false;
12965 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012966 }
12967 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012968}
12969
12970
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012971// Collect the raw data for a stack trace. Returns an array of 4
12972// element segments each containing a receiver, function, code and
12973// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012974RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012975 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012976 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012977 Handle<Object> caller = args.at<Object>(1);
12978 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012980 HandleScope scope(isolate);
12981 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012982
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012983 limit = Max(limit, 0); // Ensure that limit is not negative.
12984 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012985 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012986 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012987
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012988 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012989 // If the caller parameter is a function we skip frames until we're
12990 // under it before starting to collect.
12991 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012992 int cursor = 0;
12993 int frames_seen = 0;
12994 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012995 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012996 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012997 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012998 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012999 // Set initial size to the maximum inlining level + 1 for the outermost
13000 // function.
13001 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013002 frame->Summarize(&frames);
13003 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013004 if (cursor + 4 > elements->length()) {
13005 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13006 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013007 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013008 for (int i = 0; i < cursor; i++) {
13009 new_elements->set(i, elements->get(i));
13010 }
13011 elements = new_elements;
13012 }
13013 ASSERT(cursor + 4 <= elements->length());
13014
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013015 Handle<Object> recv = frames[i].receiver();
13016 Handle<JSFunction> fun = frames[i].function();
13017 Handle<Code> code = frames[i].code();
13018 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013019 elements->set(cursor++, *recv);
13020 elements->set(cursor++, *fun);
13021 elements->set(cursor++, *code);
13022 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013023 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013024 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013025 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013026 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013027 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013028 // Capture and attach a more detailed stack trace if necessary.
13029 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013030 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013031 return *result;
13032}
13033
13034
ager@chromium.org3811b432009-10-28 14:53:37 +000013035// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013037 ASSERT_EQ(args.length(), 0);
13038
13039 NoHandleAllocation ha;
13040
13041 const char* version_string = v8::V8::GetVersion();
13042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013043 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13044 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013045}
13046
13047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013048RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013049 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013050 OS::PrintError("abort: %s\n",
13051 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013052 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013053 OS::Abort();
13054 UNREACHABLE();
13055 return NULL;
13056}
13057
13058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013059RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013060 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013061 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013062 Object* key = args[1];
13063
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013064 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013065 Object* o = cache->get(finger_index);
13066 if (o == key) {
13067 // The fastest case: hit the same place again.
13068 return cache->get(finger_index + 1);
13069 }
13070
13071 for (int i = finger_index - 2;
13072 i >= JSFunctionResultCache::kEntriesIndex;
13073 i -= 2) {
13074 o = cache->get(i);
13075 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013076 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013077 return cache->get(i + 1);
13078 }
13079 }
13080
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013081 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013082 ASSERT(size <= cache->length());
13083
13084 for (int i = size - 2; i > finger_index; i -= 2) {
13085 o = cache->get(i);
13086 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013087 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013088 return cache->get(i + 1);
13089 }
13090 }
13091
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013092 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013093 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013094
13095 Handle<JSFunctionResultCache> cache_handle(cache);
13096 Handle<Object> key_handle(key);
13097 Handle<Object> value;
13098 {
13099 Handle<JSFunction> factory(JSFunction::cast(
13100 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13101 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013102 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013103 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013104 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013105 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013106 value = Execution::Call(factory,
13107 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013108 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013109 argv,
13110 &pending_exception);
13111 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013112 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013113
13114#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013115 if (FLAG_verify_heap) {
13116 cache_handle->JSFunctionResultCacheVerify();
13117 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013118#endif
13119
13120 // Function invocation may have cleared the cache. Reread all the data.
13121 finger_index = cache_handle->finger_index();
13122 size = cache_handle->size();
13123
13124 // If we have spare room, put new data into it, otherwise evict post finger
13125 // entry which is likely to be the least recently used.
13126 int index = -1;
13127 if (size < cache_handle->length()) {
13128 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13129 index = size;
13130 } else {
13131 index = finger_index + JSFunctionResultCache::kEntrySize;
13132 if (index == cache_handle->length()) {
13133 index = JSFunctionResultCache::kEntriesIndex;
13134 }
13135 }
13136
13137 ASSERT(index % 2 == 0);
13138 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13139 ASSERT(index < cache_handle->length());
13140
13141 cache_handle->set(index, *key_handle);
13142 cache_handle->set(index + 1, *value);
13143 cache_handle->set_finger_index(index);
13144
13145#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013146 if (FLAG_verify_heap) {
13147 cache_handle->JSFunctionResultCacheVerify();
13148 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013149#endif
13150
13151 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013152}
13153
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013155RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013156 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013157 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13158 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013159 return *isolate->factory()->NewJSMessageObject(
13160 type,
13161 arguments,
13162 0,
13163 0,
13164 isolate->factory()->undefined_value(),
13165 isolate->factory()->undefined_value(),
13166 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013167}
13168
13169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013170RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013171 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013172 return message->type();
13173}
13174
13175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013176RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013177 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013178 return message->arguments();
13179}
13180
13181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013182RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013183 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013184 return Smi::FromInt(message->start_position());
13185}
13186
13187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013188RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013189 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013190 return message->script();
13191}
13192
13193
kasper.lund44510672008-07-25 07:37:58 +000013194#ifdef DEBUG
13195// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13196// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013197RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013198 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013199 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013200#define COUNT_ENTRY(Name, argc, ressize) + 1
13201 int entry_count = 0
13202 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13203 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13204 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13205#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013206 Factory* factory = isolate->factory();
13207 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013208 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013209 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013210#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013211 { \
13212 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013213 Handle<String> name; \
13214 /* Inline runtime functions have an underscore in front of the name. */ \
13215 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013216 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013217 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13218 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013219 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013220 Vector<const char>(#Name, StrLength(#Name))); \
13221 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013222 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013223 pair_elements->set(0, *name); \
13224 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013225 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013226 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013227 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013228 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013229 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013230 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013231 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013232 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013233#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013234 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013235 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013236 return *result;
13237}
kasper.lund44510672008-07-25 07:37:58 +000013238#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013239
13240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013241RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013242 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013243 CONVERT_ARG_CHECKED(String, format, 0);
13244 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013245 String::FlatContent format_content = format->GetFlatContent();
13246 RUNTIME_ASSERT(format_content.IsAscii());
13247 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013248 LOGGER->LogRuntime(chars, elms);
13249 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013250}
13251
13252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013253RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013254 UNREACHABLE(); // implemented as macro in the parser
13255 return NULL;
13256}
13257
13258
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013259#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13260 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013261 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013262 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13263 }
13264
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013265ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013266ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13267ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13268ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13269ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13270ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13271ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13272ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13273ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13274ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13275ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13276ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13277ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13278ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13279
13280#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13281
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013282
13283RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13284 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013285 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13286 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013287 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13288}
13289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013290// ----------------------------------------------------------------------------
13291// Implementation of Runtime
13292
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013293#define F(name, number_of_args, result_size) \
13294 { Runtime::k##name, Runtime::RUNTIME, #name, \
13295 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013296
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013297
13298#define I(name, number_of_args, result_size) \
13299 { Runtime::kInline##name, Runtime::INLINE, \
13300 "_" #name, NULL, number_of_args, result_size },
13301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013302static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013303 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013304 INLINE_FUNCTION_LIST(I)
13305 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013306};
13307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013309MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13310 Object* dictionary) {
13311 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013312 ASSERT(dictionary != NULL);
13313 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13314 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013315 Object* name_symbol;
13316 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013317 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013318 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13319 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013320 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013321 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13322 String::cast(name_symbol),
13323 Smi::FromInt(i),
13324 PropertyDetails(NONE, NORMAL));
13325 if (!maybe_dictionary->ToObject(&dictionary)) {
13326 // Non-recoverable failure. Calling code must restart heap
13327 // initialization.
13328 return maybe_dictionary;
13329 }
13330 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013331 }
13332 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013333}
13334
13335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013336const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13337 Heap* heap = name->GetHeap();
13338 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013339 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013340 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013341 int function_index = Smi::cast(smi_index)->value();
13342 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013343 }
13344 return NULL;
13345}
13346
13347
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013348const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013349 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13350}
13351
13352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013353void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013354 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013355 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013356 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013357 if (isolate->heap()->new_space()->AddFreshPage()) {
13358 return;
13359 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013360
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013361 // Try to do a garbage collection; ignore it if it fails. The C
13362 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013363 isolate->heap()->CollectGarbage(failure->allocation_space(),
13364 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013365 } else {
13366 // Handle last resort GC and make sure to allow future allocations
13367 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013368 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013369 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13370 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013371 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013372}
13373
13374
13375} } // namespace v8::internal